package com.zmj.sy.mom.srv.aps.service;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DatePattern;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.google.common.collect.Lists;
import com.zmj.sy.mom.srv.aps.bean.bo.*;
import com.zmj.sy.mom.srv.aps.bean.entity.base.BaseEntity;
import com.zmj.sy.mom.srv.aps.bean.entity.order.*;
import com.zmj.sy.mom.srv.aps.bean.entity.resource.*;
import com.zmj.sy.mom.srv.aps.bean.vo.apsbatch.ApsBatchListResVo;
import com.zmj.sy.mom.srv.aps.bean.vo.apsorder.*;
import com.zmj.sy.mom.srv.aps.bean.vo.base.BaseIdReqVo;
import com.zmj.sy.mom.srv.aps.bean.vo.base.BaseListResVo;
import com.zmj.sy.mom.srv.aps.bean.vo.base.BaseSelectItemResVo;
import com.zmj.sy.mom.srv.aps.bean.vo.base.BaseSelectResVo;
import com.zmj.sy.mom.srv.aps.bean.vo.order.OrderReorderReqVo;
import com.zmj.sy.mom.srv.aps.bean.vo.order.OrderScheduleReqVo;
import com.zmj.sy.mom.srv.aps.bean.vo.order.OrderSubOrderResVo;
import com.zmj.sy.mom.srv.aps.config.ProjectConfig;
import com.zmj.sy.mom.srv.aps.config.StrategyConfig;
import com.zmj.sy.mom.srv.aps.mapper.*;
import com.zmj.sy.mom.srv.aps.utils.*;
import com.zmj.sy.mom.srv.aps.utils.algorithm.ApsAlgorithm;
import com.zmj.sy.mom.srv.aps.utils.schedulerole.ScheduleRole;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Slf4j
@RequiredArgsConstructor
@Service
public class ApsOrderService {

    private final ApsOrderMapper apsOrderMapper;

    private final StrategyConfig strategyConfig;

    private final CustomerMapper customerMapper;

    private final ProjectConfig projectConfig;

    private final OrderPhaseMapper orderPhaseMapper;

    private final GroupMapper groupMapper;

//    private final StationGroupMapper stationGroupMapper;

    private final StationMapper stationMapper;

    private final StationWeekdaySchemeMapper stationWeekdaySchemeMapper;

    private final ShiftTypeMapper shiftTypeMapper;

    private final ShiftMapper shiftMapper;

    private final StationWeekdayRuleMapper stationWeekdayRuleMapper;

    private final BreakPeriodMapper breakPeriodMapper;

    private final ApsDetailWeekdayMapper apsDetailWeekdayMapper;

    private final OrderMapper orderMapper;

    private final OrderBomMapper orderBomMapper;

    private final ApsWorkOrderMapper apsWorkOrderMapper;

    private final ApsWorkDetailMapper apsWorkDetailMapper;

    private final ReverseDetailMapper reverseDetailMapper;

    private final ApsBatchMapper apsBatchMapper;
    private final ReverseOrderMapper reverseOrderMapper;
    private final StringRedisTemplate stringRedisTemplate;
    private final WeekdayRuleMapper weekdayRuleMapper;
    private final PhaseMapper phaseMapper;


    public BaseListResVo<ApsOrderPreListResVo> preList(ApsOrderPreListReqVo reqVo) {

        LambdaQueryWrapper<ApsOrder> wrapper = Wrappers.lambdaQuery();
        wrapper.in(ApsOrder::getOrderStatus, 1, 2, 3);
        List<ApsOrder> orderPage = apsOrderMapper.selectList(wrapper);

        List<ApsOrderPreListResVo> collect = orderPage.stream()
                .map(e -> {
                    ApsOrderPreListResVo rr = new ApsOrderPreListResVo();
                    BeanUtils.copyProperties(e, rr);
                    rr.setSeq(PkgUtils.gen(e.getSeq()));
                    return rr;
                })
                .collect(Collectors.toList());
        BaseListResVo<ApsOrderPreListResVo> resVo = BaseListResVo.of(collect, ApsOrderPreListResVo.class);

        return resVo;
    }

    @Transactional(rollbackFor = Exception.class)
    public void  scheduleMove(ApsOrderScheduleReqVo reqVo, ApsBatchListResVo apsBatch1) {


        List<ApsOrder> apsOrders = apsOrderMapper.selectBatchIds(reqVo.getIds());

        // 2.数据校验
        valid(apsOrders, reqVo);

        // 3.子订单排序
        ScheduleRole scheduleRole = strategyConfig.getScheduleRole(reqVo.getSchedulingRule());
        List<ApsOrder> sortOrder = scheduleRole.sort(apsOrders, reqVo);

        // 4.构建工厂缓存信息
        ApsFactoryCache apsFactoryCache = genApsFactoryCache(sortOrder, reqVo);

        List<Integer> orderIds = sortOrder.stream().map(ApsOrder::getOrderId).distinct().collect(Collectors.toList());
        List<Order> orders = orderMapper.selectList(Wrappers.<Order>lambdaQuery().in(Order::getId, orderIds));


        LocalDateTime now = LocalDateTime.now();
        ApsBatch apsBatch = apsBatchMapper.selectById(apsBatch1.getId());
        if(apsBatch == null){
            apsBatch = new ApsBatch();
            apsBatch.setBatchNo(now.format(DatePattern.NORM_DATETIME_FORMATTER));
            apsBatch.setSchedulingRule(reqVo.getSchedulingRule());
            apsBatch.setSchedulingDateTime(now);
            apsBatch.setStatus(1);
            apsBatchMapper.insert(apsBatch);
        } else {
            apsBatch.setBatchNo(now.format(DatePattern.NORM_DATETIME_FORMATTER));
            apsBatch.setSchedulingDateTime(now);
            apsBatchMapper.updateById(apsBatch);
        }


        for (Order order : orders) {
            order.setPlanStartDateTime(null);
            order.setPlanEndDateTime(null);
            order.setBatchId(apsBatch.getId());
            orderMapper.updateById(order);
        }
        Map<Integer, Order> orderIdMap = orders.stream().collect(Collectors.toMap(Order::getId, Function.identity()));


        for (ApsOrder apsOrder : sortOrder) {

            // 构建订单缓存信息，包含所有的订单
            ApsOrderCache apsOrderCache = genApsOrderCache(apsFactoryCache, orderIdMap.get(apsOrder.getOrderId()), apsOrder, reqVo);

            // 排产所有工序
            ApsAlgorithm apsAlgorithm = strategyConfig.getApsAlgorithm(ApsAlgorithm.APS_FORWARD_SCHEDULING_CODE);

            apsAlgorithm.scheduleTask(apsFactoryCache, apsOrderCache);

            // 排产外购件
            apsAlgorithm.scheduleWl(apsFactoryCache, apsOrderCache);


            LocalDateTime planStartDateTime = apsOrderCache.getWorkOrders().stream().filter(e->e.getPlanStartDateTime() != null).min(Comparator.comparing(ApsWorkOrder::getPlanStartDateTime)).orElseThrow(() -> SyExceptionUtils.e("没有找到排产的工单")).getPlanStartDateTime();
            apsOrder.setPlanStartDateTime(planStartDateTime);

            LocalDateTime planEndDateTime = apsOrderCache.getWorkOrders().stream().filter(e->e.getPlanEndDateTime() != null).max(Comparator.comparing(ApsWorkOrder::getPlanStartDateTime)).orElseThrow(() -> SyExceptionUtils.e("没有找到排产的工单")).getPlanEndDateTime();
            apsOrder.setPlanEndDateTime(planEndDateTime);

            apsOrder.setOrderStatus(5);
            apsOrder.setLocked(2);
            apsOrderMapper.updateById(apsOrder);

            Order order = orderIdMap.get(apsOrder.getOrderId());

            order.setOrderStatus(apsOrder.getOrderStatus());
            if(order.getPlanStartDateTime() == null){
                order.setPlanStartDateTime(apsOrder.getPlanStartDateTime());
                order.setPlanEndDateTime(apsOrder.getPlanEndDateTime());
            } else {
                if(apsOrder.getPlanStartDateTime().isBefore(order.getPlanStartDateTime())){
                    order.setPlanStartDateTime(apsOrder.getPlanStartDateTime());
                }
                if(apsOrder.getPlanEndDateTime().isAfter(order.getPlanEndDateTime())){
                    order.setPlanEndDateTime(apsOrder.getPlanEndDateTime());
                }
            }

            orderMapper.updateById(order);

        }

    }

    @Transactional(rollbackFor = Exception.class)
    public ApsBatch schedule(ApsOrderScheduleReqVo reqVo, ApsBatch apsBatch) {

        List<ApsOrder> apsOrders = apsOrderMapper.selectBatchIds(reqVo.getIds());

        // 2.数据校验
        valid(apsOrders, reqVo);

        // 3.子订单排序
        ScheduleRole scheduleRole = strategyConfig.getScheduleRole(reqVo.getSchedulingRule());
        List<ApsOrder> sortOrder = scheduleRole.sort(apsOrders, reqVo);

        // 4.构建工厂缓存信息
        ApsFactoryCache apsFactoryCache = genApsFactoryCache(sortOrder, reqVo);
        apsFactoryCache.setBottleneckPhaseCode(reqVo.getBottleneckPhaseCode());

        List<Integer> orderIds = sortOrder.stream().map(ApsOrder::getOrderId).distinct().collect(Collectors.toList());
        List<Order> orders = orderMapper.selectList(Wrappers.<Order>lambdaQuery().in(Order::getId, orderIds));

        LocalDateTime now = LocalDateTime.now();
        if(apsBatch == null){
            apsBatch = new ApsBatch();
            apsBatch.setBatchNo(now.format(DatePattern.NORM_DATETIME_FORMATTER));
            apsBatch.setSchedulingRule(reqVo.getSchedulingRule());
            apsBatch.setSchedulingDateTime(now);
            apsBatch.setStatus(1);
            apsBatchMapper.insert(apsBatch);
        } else {
            apsBatch.setBatchNo(now.format(DatePattern.NORM_DATETIME_FORMATTER));
            apsBatch.setSchedulingDateTime(now);
            apsBatchMapper.updateById(apsBatch);
        }

        for (Order order : orders) {
            order.setPlanStartDateTime(null);
            order.setPlanEndDateTime(null);
            order.setBatchId(apsBatch.getId());
            orderMapper.updateById(order);
        }
        Map<Integer, Order> orderIdMap = orders.stream().collect(Collectors.toMap(Order::getId, Function.identity()));


        for (ApsOrder apsOrder : sortOrder) {

            // 构建订单缓存信息，包含所有的订单
            ApsOrderCache apsOrderCache = genApsOrderCache(apsFactoryCache, orderIdMap.get(apsOrder.getOrderId()), apsOrder, reqVo);

            // 排产所有工序
            ApsAlgorithm apsAlgorithm = strategyConfig.getApsAlgorithm(ApsAlgorithm.APS_FORWARD_SCHEDULING_CODE);
            apsAlgorithm.scheduleTask(apsFactoryCache, apsOrderCache);


//            if (CollUtil.isNotEmpty(apsFactoryCache.getBottleneckPhaseCode())) {
//                ApsAlgorithm apsAlgorithm1 = strategyConfig.getApsAlgorithm(ApsAlgorithm.APS_BOTTLENECK_ALGORITHM_CODE);
//                apsAlgorithm1.scheduleTask(apsFactoryCache, apsOrderCache);
//            }

            // 排产外购件
            apsAlgorithm.scheduleWl(apsFactoryCache, apsOrderCache);


            LocalDateTime planStartDateTime = apsOrderCache.getWorkOrders().stream().filter(e->e.getPlanStartDateTime() != null).min(Comparator.comparing(ApsWorkOrder::getPlanStartDateTime)).orElseThrow(() -> SyExceptionUtils.e("没有找到排产的工单")).getPlanStartDateTime();
            apsOrder.setPlanStartDateTime(planStartDateTime);

            LocalDateTime planEndDateTime = apsOrderCache.getWorkOrders().stream().filter(e->e.getPlanEndDateTime() != null).max(Comparator.comparing(ApsWorkOrder::getPlanStartDateTime)).orElseThrow(() -> SyExceptionUtils.e("没有找到排产的工单")).getPlanEndDateTime();
            apsOrder.setPlanEndDateTime(planEndDateTime);

            apsOrder.setOrderStatus(5);
            apsOrder.setLocked(2);
            apsOrderMapper.updateById(apsOrder);

            Order order = orderIdMap.get(apsOrder.getOrderId());

            order.setOrderStatus(apsOrder.getOrderStatus());
            if(order.getPlanStartDateTime() == null){
                order.setPlanStartDateTime(apsOrder.getPlanStartDateTime());
                order.setPlanEndDateTime(apsOrder.getPlanEndDateTime());
            } else {
                if(apsOrder.getPlanStartDateTime().isBefore(order.getPlanStartDateTime())){
                    order.setPlanStartDateTime(apsOrder.getPlanStartDateTime());
                }
                if(apsOrder.getPlanEndDateTime().isAfter(order.getPlanEndDateTime())){
                    order.setPlanEndDateTime(apsOrder.getPlanEndDateTime());
                }
            }

            orderMapper.updateById(order);

        }

        return apsBatch;

    }

    @Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
    public void clear(ApsOrder apsOrder) {
        apsWorkOrderMapper.deleteOrderId(apsOrder.getId());
        apsWorkDetailMapper.deleteOrderId(apsOrder.getId());
        apsDetailWeekdayMapper.deleteOrderId(apsOrder.getId());
    }


    public ApsOrderCache genApsOrderCache(ApsFactoryCache apsFactoryCache, Order order, ApsOrder apsOrder, ApsOrderScheduleReqVo reqVo) {

//        apsWorkOrderMapper.delete(Wrappers.<ApsWorkOrder>lambdaQuery().eq(ApsWorkOrder::getApsOrderId, apsOrder.getId()));
//        apsWorkDetailMapper.delete(Wrappers.<ApsWorkDetail>lambdaQuery().eq(ApsWorkDetail::getApsOrderId, apsOrder.getId()));


        ApsOrderCache cache = new ApsOrderCache();

        cache.setOrder(order);
        cache.setApsOrder(apsOrder);
        cache.setStartDateTime(reqVo.getStartDateTime());

        List<OrderBom> orderBoms = orderBomMapper.lambdaQuery().eq(OrderBom::getOrderId, order.getId()).list();
        cache.setOrderBoms(orderBoms);

        List<OrderPhase> orderPhases = orderPhaseMapper.selectList(Wrappers.<OrderPhase>lambdaQuery().eq(OrderPhase::getOrderId, order.getId()));
//        orderPhases = orderPhases.stream().filter(e -> !e.getPhaseCode().equals("YC")).collect(Collectors.toList());
        cache.setOrderPhases(orderPhases);

        List<ApsWorkOrder> apsBoms = orderBoms.stream()
//                .filter(e-> !e.getMaterCode().startsWith("0"))// 跳过原材料
                .map(e -> {
                    ApsWorkOrder apsBom = MkBeanUtils.copyProperties(e, ApsWorkOrder.class);

                    apsBom.setApsOrderId(apsOrder.getId());
                    apsBom.setBomId(e.getId());
                    apsBom.setBomPid(e.getPid());
                    apsBom.setId(null);
                    apsBom.setPid(null);
                    apsBom.setStatus(1);
                    apsBom.setFinishCount(new BigDecimal(0));
                    apsBom.setTotalCount(e.getTotalCount());
                    apsBom.setOrderCount(e.getTotalCount().multiply(new BigDecimal(apsOrder.getOrderQty())));
                    apsBom.setOrderType(order.getOrderType());
                    apsBom.setPlmId(e.getPlmId());
                    return apsBom;
                })
//                .filter(e -> !(e.getPlmId().startsWith("010") || e.getPlmId().startsWith("020") || e.getPlmId().startsWith("050")))
                .collect(Collectors.toList());

        Map<Integer, List<ApsWorkOrder>> pidBomMap = apsBoms.stream().filter(e->e.getBomPid() != null).collect(Collectors.groupingBy(ApsWorkOrder::getBomPid));
        List<ApsWorkOrder> parentBoms = apsBoms.stream().filter(e -> e.getBomPid() == null).collect(Collectors.toList());
        if(CollUtil.isNotEmpty(parentBoms)){
            apsWorkOrderMapper.insertBatch(parentBoms);
        }

        while (CollUtil.isNotEmpty(parentBoms)) {

            List<ApsWorkOrder> temp = new ArrayList<>();
            for (ApsWorkOrder parentBom : parentBoms) {
                List<ApsWorkOrder> apsBomChildren = pidBomMap.get(parentBom.getBomId());
                if (CollUtil.isEmpty(apsBomChildren)) {
                    continue;
                }

                if(parentBom.getWorkChain().equals("WL")){
                    continue;
                }


                for (ApsWorkOrder apsBom : apsBomChildren) {
                    apsBom.setPid(parentBom.getId());
                }
                temp.addAll(apsBomChildren);

            }

            parentBoms = temp;
            if(CollUtil.isNotEmpty(temp)){
                apsWorkOrderMapper.insertBatchSomeColumn(temp);
            }
        }

        apsBoms = apsBoms.stream().filter(e -> e.getId() != null).collect(Collectors.toList());

        cache.setWorkOrders(apsBoms);


        Map<Integer, ApsWorkOrder> bomIdMap = apsBoms.stream().collect(Collectors.toMap(ApsWorkOrder::getBomId, Function.identity()));

        List<ReverseDetail> reverseDetails = reverseDetailMapper.selectList(Wrappers.<ReverseDetail>lambdaQuery().eq(ReverseDetail::getReverseOrderId, apsOrder.getReverseId()).orderByAsc(ReverseDetail::getReverseEndTime));
        Map<String, ReverseDetail> collect1 = reverseDetails.stream().collect(Collectors.toMap(e -> e.getBomId() + "---" + e.getPhaseId(), Function.identity(), (e1, e2) -> e1.getReverseEndTime().isBefore(e2.getReverseEndTime()) ? e1 : e2));
        reverseDetails = collect1.values().stream().sorted((e1, e2)->{
            int ii = e1.getReverseEndTime().compareTo(e2.getReverseEndTime());
            if(ii != 0){
                return ii;
            }

            ii = e1.getLevel().compareTo(e2.getLevel());
            if(ii != 0){
                return -ii;
            }

            return e1.getPhaseId().compareTo(e2.getPhaseId());

//            Comparator.comparing(ReverseDetail::getReverseEndTime).thenComparing(ReverseDetail::getLevel).thenComparing(ReverseDetail::getPhaseId)
        }).collect(Collectors.toList());


        Map<Integer, OrderPhase> orderPhaseMap = orderPhases.stream().collect(Collectors.toMap(BaseEntity::getId, Function.identity()));

        List<ApsWorkDetail> apsWorkDetails = new ArrayList<>(reverseDetails.size());
        for (int i = 0; i < reverseDetails.size(); i++) {
            ReverseDetail e = reverseDetails.get(i);

            ApsWorkDetail apsWorkDetail = new ApsWorkDetail();
            apsWorkDetail.setOrderId(e.getOrderId());
            apsWorkDetail.setApsOrderId(apsOrder.getId());
            apsWorkDetail.setApsWorkOrderId(bomIdMap.get(e.getBomId()).getId());
            apsWorkDetail.setApsWorkOrderPid(bomIdMap.get(e.getBomId()).getPid());

            OrderPhase orderPhase = orderPhaseMap.get(e.getPhaseId());

            if(apsFactoryCache.getIgnorePhaseCode().contains(orderPhase.getPhaseCode())){
                continue;
            }

            apsWorkDetail.setPhaseId(orderPhase.getId());
            apsWorkDetail.setWorkTime(orderPhase.getWorkTime());

            apsWorkDetail.setPhaseSeq(orderPhase.getPhaseSeq());
            apsWorkDetail.setPhaseCode(orderPhase.getPhaseCode());
            apsWorkDetail.setPhaseName(orderPhase.getPhaseName());
            apsWorkDetail.setPhaseCode(orderPhase.getPhaseCode());
            apsWorkDetail.setMaterNo(orderPhase.getMaterNo());
            apsWorkDetail.setMaterName(orderPhase.getMaterName());
            apsWorkDetail.setGroupCode(orderPhase.getWorkGroupNumber());
            apsWorkDetail.setOrderType(order.getOrderType());


            // 从倒排表里取
            apsWorkDetail.setPartCount(bomIdMap.get(e.getBomId()).getPartCount());
            apsWorkDetail.setTotalCount(bomIdMap.get(e.getBomId()).getOrderCount());
            apsWorkDetail.setGroupId(e.getGroupId());
            apsWorkDetail.setProcessCount(new BigDecimal(0));
            apsWorkDetail.setFinishCount(new BigDecimal(0));
            apsWorkDetail.setStatus(1);
            apsWorkDetail.setStationGroupId(e.getStationGroupId());

            apsWorkDetail.setDetailSeq(i + 1);
            apsWorkDetail.setApsOrderId(apsOrder.getId());
            apsWorkDetail.setReverseDetailId(e.getId());
            apsWorkDetail.setPlmId(bomIdMap.get(e.getBomId()).getPlmId());
            apsWorkDetails.add(apsWorkDetail);
        }


        Map<String, List<Station>> masterStationMap = apsFactoryCache.getMasterStationMap();
        List<ApsWorkDetail> collect = apsWorkDetails.stream()
                .flatMap(e -> {

                    List<Station> stationList = masterStationMap.get(e.getGroupCode());
                    if(CollUtil.isEmpty(stationList)){
                        throw SyExceptionUtils.e("{}没有工位", e.getGroupCode());
                    }
                    Integer smallTransfer = stationList.get(0).getSmallTransfer();
                    if (smallTransfer == null || smallTransfer <= 0) {
                        return Stream.of(e);
                    }

                    int div = e.getTotalCount().divide(new BigDecimal(smallTransfer), 0, RoundingMode.DOWN).intValue();

                    BigDecimal subtract = e.getTotalCount().subtract(new BigDecimal(smallTransfer).multiply(new BigDecimal(div)));


                    List<ApsWorkDetail> l = new ArrayList<>();

                    for (int i = 0; i < div; i++) {
                        ApsWorkDetail apsWorkDetail = MkBeanUtils.copyProperties(e, ApsWorkDetail.class);
                        apsWorkDetail.setTotalCount(new BigDecimal(smallTransfer));
                        l.add(apsWorkDetail);
                    }

                    if(subtract.compareTo(BigDecimal.ZERO) > 0){
                        ApsWorkDetail apsWorkDetail = MkBeanUtils.copyProperties(e, ApsWorkDetail.class);
                        apsWorkDetail.setTotalCount(subtract);
                        l.add(apsWorkDetail);
                    }

                    return l.stream();

                })
                .collect(Collectors.toList());


        if(CollUtil.isNotEmpty(collect)){
            for (ApsWorkDetail apsWorkDetail : collect) {
                apsWorkDetail.setType(2);
            }
            apsWorkDetailMapper.insertBatchSomeColumn(collect);
        }


//        1。* 拿到BOM，转化成workorder
//        2。* 拿到工序,转化成WorkDetail
//        3。* 填充WorkDetail的顺序
//        4。* 找到工作组下的工位，并根据转运数量进行扁平化WorkDetail
//        5。* 把WorkDetail转化Task

        Map<Integer, OrderBom> orderBomMap = orderBoms.stream().collect(Collectors.toMap(BaseEntity::getId, Function.identity()));


        List<ApsTask> tasks = collect.stream()
                .map(e -> {
                    ApsTask t = new ApsTask(e);
                    t.setConsumerStatus(1);
                    t.setConsumerCount(new BigDecimal(0));
                    return t;
                })
                .sorted(Comparator.comparingInt((ApsTask e) -> e.getApsWorkDetail().getDetailSeq()).thenComparingInt(e -> orderBomMap.get(orderPhaseMap.get(e.getApsWorkDetail().getPhaseId()).getBomId()).getLevel()))
                .collect(Collectors.toList());

        cache.setTaskList(tasks);


        Map<Integer, Map<Integer, List<ApsTask>>> workOrderIdPhaseSeqMap = tasks.stream().collect(Collectors.groupingBy(ApsTask::getApsWorkOrderId, Collectors.groupingBy(ApsTask::getPhaseSeq)));
        cache.setWorkOrderIdPhaseSeqMap(workOrderIdPhaseSeqMap);

        Map<Integer, List<ApsTask>> workOrderPidMap = tasks.stream().filter(e -> e.getApsWorkOrderPid() != null).collect(Collectors.groupingBy(ApsTask::getApsWorkOrderPid));
        cache.setWorkOrderPidMap(workOrderPidMap);

        return cache;
    }

    public ApsFactoryCache genApsFactoryCache(List<ApsOrder> apsOrders, ApsOrderScheduleReqVo reqVo) {
        ApsFactoryCache apsFactoryCache = new ApsFactoryCache();

        apsFactoryCache.setPreview(reqVo.getPreview());

        // 设置工厂信息
        apsFactoryCache.setFactoryCode(projectConfig.getFactoryCode());

        // 设置客户信息
        List<Integer> customerList = apsOrders.stream().map(ApsOrder::getCustomerId).distinct().collect(Collectors.toList());
        if(CollUtil.isNotEmpty(customerList)){
            List<Customer> customers = customerMapper.selectBatchIds(customerList);
            apsFactoryCache.setCustomers(customers);
        }

        // 工作组信息
        List<String> groupNumberString = orderPhaseMapper.selectGroupList(Wrappers.<OrderPhase>query()
                .in("order_id", apsOrders.stream().map(BaseEntity::getId).collect(Collectors.toList()))
        );
        List<Group> groups = groupMapper.lambdaQuery().in(Group::getMyCode, groupNumberString).list();
        apsFactoryCache.setGroups(groups);

//        // 工作组工位关联
//        List<StationGroup> stationGroups = stationGroupMapper.selectList(Wrappers.<StationGroup>lambdaQuery().in(StationGroup::getGroupId, groups.stream().map(BaseEntity::getId).collect(Collectors.toList())));
//        apsFactoryCache.setStationGroups(stationGroups);

        // 工位信息
//        List<Integer> stationIds = stationGroups.stream().map(StationGroup::getStationId).distinct().collect(Collectors.toList());
//        List<Station> stations = stationMapper.selectBatchIds(stationIds);
        List<Station> stations = stationMapper.lambdaQuery().in(Station::getGroupId, groups.stream().map(BaseEntity::getId).collect(Collectors.toList())).list();
        List<Integer> stationIds = stations.stream().map(Station::getId).collect(Collectors.toList());

        for (Station station : stations) {
            if(station.getEnterTime() == null || station.getEnterTime() < 0){
                station.setEnterTime(0);
            }

            if(station.getOutTime() == null || station.getOutTime() < 0){
                station.setOutTime(0);
            }

            if(station.getChangTime() == null || station.getChangTime() < 0){
                station.setChangTime(0);
            }
        }

        apsFactoryCache.setStations(stations);

        // 快捷从工作组找到主工位列表
//        Map<Integer, List<StationGroup>> stationGroupMap = stationGroups.stream().filter(e -> e.getDefaultGroup().equals(1)).collect(Collectors.groupingBy(StationGroup::getGroupId));
        Map<Integer, Station> stationMap = stations.stream().collect(Collectors.toMap(BaseEntity::getId, Function.identity()));
        Map<Integer, List<Station>> stationGroupIdMap = stations.stream().collect(Collectors.groupingBy(Station::getGroupId));
        Map<String, List<Station>> masterStationMap = new HashMap<>();
        for (Group group : groups) {

//            List<StationGroup> stationGroups1 = stationGroupMap.get(group.getId());
//            if(CollUtil.isEmpty(stationGroups1)){
//                continue;
//            }

//            List<Station> value = stationGroupMap.get(group.getId())
//                    .stream()
//                    .map(e -> stationMap.get(e.getStationId()))
//                    .collect(Collectors.toList());
            List<Station> value = stationGroupIdMap.get(group.getId());

            masterStationMap.put(group.getMyCode(), value);
        }

        apsFactoryCache.setMasterStationMap(masterStationMap);

        // 工位日历
//        List<StationWeekdayScheme> stationWeekdaySchemes = stationWeekdaySchemeMapper.selectList(Wrappers.<StationWeekdayScheme>lambdaQuery().in(StationWeekdayScheme::getStationId, stationIds));
        List<ShiftType> shiftTypes = shiftTypeMapper.selectBatchIds(stationIds);
        List<Integer> shiftTypeIds = shiftTypes.stream().map(BaseEntity::getId).collect(Collectors.toList());
        List<WeekdayRule> stationWeekdayRules = weekdayRuleMapper.lambdaQuery().in(WeekdayRule::getShiftTypeId, shiftTypeIds).list();
        List<Shift> shifts = shiftMapper.lambdaQuery().in(Shift::getShiftTypeId, shiftTypeIds).list();
        List<Integer> shiftIds = shifts.stream().map(BaseEntity::getId).collect(Collectors.toList());
        List<BreakPeriod> breakPeriods = breakPeriodMapper.lambdaQuery().in(BreakPeriod::getShiftId, shiftIds).list();

//        apsFactoryCache.setStationWeekdaySchemes(stationWeekdaySchemes);
        apsFactoryCache.setStationWeekdayRules(stationWeekdayRules);
        apsFactoryCache.setShiftTypes(shiftTypes);
        apsFactoryCache.setShifts(shifts);
        apsFactoryCache.setBreakPeriods(breakPeriods);

        // 拼装设备时间链
        LocalDate startDate = reqVo.getStartDateTime().toLocalDate();
        int day = 10;
        LocalDate endDate = startDate.plusDays(day);
        apsFactoryCache.setMachines(stations.stream().map(ApsMachine::new).collect(Collectors.toList()));
        apsFactoryCache.addDay(startDate, day);

        // 生产工单占位填充
        LambdaQueryWrapper<ApsDetailWeekday> wrapper = Wrappers.lambdaQuery();
        wrapper.ge(ApsDetailWeekday::getShiftDay, startDate);
        wrapper.le(ApsDetailWeekday::getShiftDay, endDate);
        wrapper.ge(ApsDetailWeekday::getState, 2);
        wrapper.ne(ApsDetailWeekday::getState, 4);
        wrapper.in(ApsDetailWeekday::getOrderType, 1, 3, 4);
        wrapper.in(ApsDetailWeekday::getStationId, stations.stream().map(Station::getId).distinct().collect(Collectors.toList()));
        wrapper.orderByAsc(ApsDetailWeekday::getPlanStartDateTime);
        List<ApsDetailWeekday> apsDetailWeekdays = apsDetailWeekdayMapper.selectList(wrapper);
//        List<ApsDetailWeekday> apsDetailWeekdays = new ArrayList<>();

        if(CollUtil.isNotEmpty(apsDetailWeekdays)){
            List<Integer> collect1 = apsDetailWeekdays.stream().map(ApsDetailWeekday::getApsWorkDetailId).distinct().collect(Collectors.toList());
            Map<Integer, ApsWorkDetail> detailMap = apsWorkDetailMapper.selectBatchIds(collect1)
                    .stream()
                    .collect(Collectors.toMap(ApsWorkDetail::getId, Function.identity()));

            apsFactoryCache.addTasks(apsDetailWeekdays, detailMap);
        }


        Map<String, List<ApsMachine>> groupCodeMachineMap = new HashMap<>();
        Map<Integer, ApsMachine> idApsMachineMap = apsFactoryCache.getMachines().stream().collect(Collectors.toMap(ApsMachine::getId, Function.identity()));

        for (Map.Entry<String, List<Station>> entry : masterStationMap.entrySet()) {
            List<Station> collect = entry.getValue().stream().filter(e -> e.getWorkAbility() == null).collect(Collectors.toList());
            if(CollUtil.isNotEmpty(collect)){
                throw SyExceptionUtils.e("工位{}没有工作能力", entry.getValue().get(0).getName());
            }
            groupCodeMachineMap.put(entry.getKey(), entry.getValue().stream().map(e -> idApsMachineMap.get(e.getId())).collect(Collectors.toList()));
        }

        // 激光切割工作组合并
        /*
        List<String> joinGroup = Arrays.asList("1-2_JGQG_00", "1-3_JGQG_00");
        List<ApsMachine> temp = new ArrayList<>();
        for (String groupCode : joinGroup) {
            // 取出原本工作组的数据加入缓存
            List<ApsMachine> apsMachines = groupCodeMachineMap.get(groupCode);
            if(apsMachines == null){
                continue;
            }
            temp.addAll(apsMachines);
            // 缓存的指针给加工机器，以便多个工作组共享
            groupCodeMachineMap.put(groupCode, temp);
        }
         */


        apsFactoryCache.setGroupCodeMachineMap(groupCodeMachineMap);

        apsFactoryCache.setIgnorePhaseCode(projectConfig.getIgnorePhaseCodeList());

        apsFactoryCache.setPzCode(WorkshopProp.PZ_PHASE_CODE);
        apsFactoryCache.setPzSecond(WorkshopProp.PZ_SECOND);

        List<Phase> phaseList = phaseMapper.lambdaQuery().list();
        Map<String, Phase> phaseCodeMap = phaseList.stream().collect(Collectors.toMap(Phase::getMyCode, Function.identity()));
        apsFactoryCache.setPhaseCodeMap(phaseCodeMap);

        return apsFactoryCache;
    }

    public void fillIds(ApsOrderScheduleReqVo reqVo) {
        // 从数据库取出待排产的数据
        LambdaQueryWrapper<Order> wrap = Wrappers.<Order>lambdaQuery()
                .in(Order::getOrderStatus, 1, 3);
        List<Order> apsOrders = orderMapper.selectList(wrap);
        List<Integer> collect = apsOrders.stream().map(BaseEntity::getId).collect(Collectors.toList());
        reqVo.setIds(collect);

        if (CollUtil.isEmpty(reqVo.getIds())) {
            throw SyExceptionUtils.e("没有待排产的数据");
        }

    }

    public void valid(List<ApsOrder> apsOrders, ApsOrderScheduleReqVo reqVo) {
        for (ApsOrder apsOrder : apsOrders) {
            // 数据校验 - 检查交付日期
//            if (apsOrder.getDeliveryDate() == null) {
//                throw SyExceptionUtils.e("交付日期不能为空");
//            }
            // 数据校验 - 检查开始时间
//            if (reqVo.getStartDateTime() == null) {
//                throw SyExceptionUtils.e("开始时间不能为空");
//            }

            // 数据校验 - 客户信息
//            if (apsOrder.getCustomerId() == null) {
//                throw SyExceptionUtils.e("客户信息不能为空");
//            }

        }

    }

    @Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
    public void lock(ApsOrderScheduleReqVo reqVo) {

        // 1.检查redis是否有锁定状态，如果有则提示，并且不排产
        ValueOperations<String, String> valOperation = stringRedisTemplate.opsForValue();
        String lockFlag = valOperation.get(ApsConstant.APS_SCHEDULING_LOCK);
        if (StringUtils.hasText(lockFlag)) {
            throw SyExceptionUtils.e("{} 等订单排产中!", lockFlag);
        }

        // 3.把待排产的订单号放入redis，设置锁定状态
        String redisVal = reqVo.getCacheOrder().stream().map(e -> e.getConstructNo() + "_" + e.getMaterName()).collect(Collectors.joining(","));
        valOperation.set(ApsConstant.APS_SCHEDULING_LOCK, redisVal, 1, TimeUnit.DAYS);

        Integer i = apsOrderMapper.selectCount(Wrappers.<ApsOrder>lambdaQuery()
                .in(ApsOrder::getId, reqVo.getIds())
                .eq(ApsOrder::getOrderStatus, 4)
        );
        if(i > 0){
            throw SyExceptionUtils.e("已有正在排产的订单，请稍后再试");
        }

        apsOrderMapper.update(null, Wrappers.<ApsOrder>lambdaUpdate()
                .set(ApsOrder::getOrderStatus, 4)
                .in(ApsOrder::getId, reqVo.getIds())
        );
    }

    @Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
    public void unlock(ApsOrderScheduleReqVo reqVo, int status) {

        // 清空锁定标志位
        stringRedisTemplate.delete(ApsConstant.APS_SCHEDULING_LOCK);


        if (CollUtil.isEmpty(reqVo.getIds())) {
            return;
        }

        apsOrderMapper.update(null, Wrappers.<ApsOrder>lambdaUpdate()
                .set(ApsOrder::getOrderStatus, status)
                .eq(ApsOrder::getOrderStatus, 4)
                .in(ApsOrder::getId, reqVo.getIds())
        );


    }

    @Transactional
    public void publish(ApsOrderPublishReqVo reqVo) {

        // 判断是否有未排产或者排产中的，如果有则提示退出

        Integer noStatus = apsOrderMapper.selectCount(Wrappers.<ApsOrder>lambdaQuery()
                .eq(ApsOrder::getOrderStatus, 1)
        );
        if(noStatus > 0){
            throw SyExceptionUtils.e("有未排产的记录");
        }

        Integer processStatus = apsOrderMapper.selectCount(Wrappers.<ApsOrder>lambdaQuery()
                .eq(ApsOrder::getOrderStatus, 2)
        );
        if(processStatus > 0){
            throw SyExceptionUtils.e("有正在排产中的数据");
        }


        List<ApsOrder> apsOrders = apsOrderMapper.selectList(Wrappers.<ApsOrder>lambdaQuery()
                .eq(ApsOrder::getOrderStatus, 3)
        );

        if(CollUtil.isEmpty(apsOrders)){
            throw SyExceptionUtils.e("没有找到已排产的数据");
        }

        List<Integer> collect = apsOrders.stream().map(ApsOrder::getOrderId).collect(Collectors.toList());

        orderMapper.update(null, Wrappers.<Order>lambdaUpdate()
                .set(Order::getOrderStatus, 5)
                .in(Order::getId, collect)
        );

        List<Integer> apsIds = apsOrders.stream().map(BaseEntity::getId).collect(Collectors.toList());



        apsOrderMapper.update(null, Wrappers.<ApsOrder>lambdaUpdate()
                .set(ApsOrder::getOrderStatus, 5)
                .in(BaseEntity::getId, apsIds)
        );

        // 更新apsWorkOrder
        apsWorkOrderMapper.update(null, Wrappers.<ApsWorkOrder>lambdaUpdate()
                .set(ApsWorkOrder::getStatus, 2)
                .in(ApsWorkOrder::getApsOrderId, apsIds)
        );
        // 更新apsWorkDetailMapper
        apsWorkDetailMapper.update(null, Wrappers.<ApsWorkDetail>lambdaUpdate()
                .set(ApsWorkDetail::getStatus, 2)
                .in(ApsWorkDetail::getApsOrderId, apsIds)
        );
        // 更新apsDetailWeekdayMapper
        apsDetailWeekdayMapper.update(null, Wrappers.<ApsDetailWeekday>lambdaUpdate()
                .set(ApsDetailWeekday::getState, 2)
                .in(ApsDetailWeekday::getApsOrderId, apsIds)
        );

    }

    public BaseListResVo<ApsOrderPubListResVo> pubList(ApsOrderPubListReqVo reqVo) {
        LambdaQueryWrapper<ApsOrder> wrapper = Wrappers.lambdaQuery();
        wrapper.ge(ApsOrder::getOrderStatus, 5);
        List<ApsOrder> orderPage = apsOrderMapper.selectList(wrapper);

        List<ApsOrderPubListResVo> collect = orderPage.stream()
                .map(e -> {
                    ApsOrderPubListResVo rr = new ApsOrderPubListResVo();
                    BeanUtils.copyProperties(e, rr);
                    rr.setSeq(PkgUtils.gen(e.getSeq()));
                    return rr;
                })
                .collect(Collectors.toList());
        return BaseListResVo.of(collect, ApsOrderPubListResVo.class);
    }

    @Transactional
    public void lock(ApsOrderPublishReqVo reqVo) {
        LambdaUpdateWrapper<ApsOrder> wrapper = Wrappers.lambdaUpdate();
        wrapper.set(ApsOrder::getLocked, 2);
        wrapper.in(ApsOrder::getId, reqVo.getIds());
        wrapper.ge(ApsOrder::getOrderStatus, 5);
        apsOrderMapper.update(null, wrapper);
    }

    @Transactional
    public void unlock(ApsOrderPublishReqVo reqVo) {
        LambdaUpdateWrapper<ApsOrder> wrapper = Wrappers.lambdaUpdate();
        wrapper.set(ApsOrder::getLocked, 1);
        wrapper.in(ApsOrder::getId, reqVo.getIds());
        wrapper.ge(ApsOrder::getOrderStatus, 5);
        apsOrderMapper.update(null, wrapper);

    }

    public BaseListResVo<ApsOrderGanttChartResVo> orderGanttChart(ApsOrderOrderGanttChartReqVo reqVo) {
        // 1.查出 ApsOrder 的信息，如果没有开始时间，则传入订单的开始时间，如果没有结束时间，则传入订单的结束时间

        ApsOrder apsOrder = apsOrderMapper.selectById(reqVo.getId());

        if(apsOrder.getOrderStatus() < 5){
            throw SyExceptionUtils.e("订单未排产完成");
        }

        if(reqVo.getStartDate() == null){
            reqVo.setStartDate(apsOrder.getPlanStartDateTime());
        }

        if(reqVo.getEndDate() == null) {
            reqVo.setEndDate(apsOrder.getPlanEndDateTime());
        }

        // 2.查出某个 ApsWorkDetail 下这个时间段内的所有的排产信息
        LambdaQueryWrapper<ApsWorkDetail> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(ApsWorkDetail::getApsOrderId, reqVo.getId());
        wrapper.ge(ApsWorkDetail::getPlanStartDateTime, reqVo.getStartDate());
        wrapper.le(ApsWorkDetail::getPlanEndDateTime, reqVo.getEndDate());
        return orderGanttChart(wrapper, 1);
    }

    public BaseListResVo<ApsOrderGanttChartResVo> orderGanttChart(LambdaQueryWrapper<ApsWorkDetail> wrapper, int type) {
        wrapper.eq(ApsWorkDetail::getDeleted, 0);
        List<ApsWorkDetail> apsWorkDetails = apsWorkDetailMapper.selectList(wrapper);
        if(CollUtil.isEmpty(apsWorkDetails)){
            return BaseListResVo.empty();
        }

        Map<Integer, List<ApsWorkDetail>> collect = apsWorkDetails.stream().collect(Collectors.groupingBy(ApsWorkDetail::getStationId));

        List<ApsWorkOrder> apsWorkOrderList = apsWorkOrderMapper.selectBatchIds(apsWorkDetails.stream().map(ApsWorkDetail::getApsWorkOrderId).distinct().collect(Collectors.toList()));
        Map<Integer, ApsWorkOrder> apsWorkOrderIdMap = apsWorkOrderList.stream().collect(Collectors.toMap(BaseEntity::getId, Function.identity()));


        List<Station> stationList = stationMapper.selectBatchIds(collect.keySet());
        Map<Integer, Station> stationIdMap = stationList.stream().collect(Collectors.toMap(BaseEntity::getId, Function.identity()));

        List<String> colors = Lists.newArrayList("#93E5A0", "#F1A599", "#3D93F6", "#F6AF43", "#6BC471", "#47CBE6", "#9FD2FF", "#B29FFF", "#FFDA61", "#FF7F50", "#FFD299", "#8FBF9F");
        Map<Integer, String> subOrderIdMap = new HashMap<>();

        int i = 0;

        List<ApsOrderGanttChartResVo> res = new ArrayList<>();
        for (Map.Entry<Integer, List<ApsWorkDetail>> entry : collect.entrySet()) {
            ApsOrderGanttChartResVo resVo = new ApsOrderGanttChartResVo();
            Station station = stationIdMap.get(entry.getKey());
            resVo.setStationId(station.getId());
            resVo.setStationName(station.getName());
            resVo.setStationCode(station.getMyCode());

            res.add(resVo);
            List<ApsWorkDetail> details = entry.getValue();
            for (ApsWorkDetail detail : details) {
                ApsOrderGanttChartArrayResVo rr = new ApsOrderGanttChartArrayResVo();
                rr.setStart(detail.getPlanStartDateTime());
                rr.setEnd(detail.getPlanEndDateTime());
                rr.setId(detail.getId());
                rr.setOrderId(detail.getOrderId());
                rr.setApsOrderId(detail.getApsOrderId());
                rr.setApsWorkOrderId(detail.getApsWorkOrderId());
                rr.setApsWorkOrderPid(detail.getApsWorkOrderPid());
                rr.setPhaseCode(detail.getPhaseCode());
                rr.setPhaseName(detail.getPhaseName());
                rr.setBomName(detail.getMaterName());
                rr.setBomCode(detail.getMaterNo());
                rr.setCount(detail.getTotalCount());
                rr.setFinishCount(detail.getFinishCount());
                rr.setPlmId(rr.getBomCode());
                rr.setWorkTimeMinutes(new BigDecimal(detail.getWorkTime()).divide(new BigDecimal(60), 2, RoundingMode.HALF_UP));
                rr.setPlanTimeMinutes(new BigDecimal(detail.getTotalWorkTime()).divide(new BigDecimal(60), 2, RoundingMode.HALF_UP));
                if (type == 1) {
                    rr.setColor(colors.get(i++ % colors.size()));
                } else if (type == 2){
                    // 取出所有的订单，给订单去重，并给订单配上颜色
                    String s = subOrderIdMap.computeIfAbsent(rr.getApsOrderId(), k -> colors.get(subOrderIdMap.size() % colors.size()));
                    rr.setColor(s);

                }

                rr.setGroupCode(detail.getGroupCode());
                ApsWorkOrder apsWorkOrder = apsWorkOrderIdMap.get(detail.getApsWorkOrderId());

                rr.setErpCode(apsWorkOrder.getErpCode());
                rr.setWorkChain(apsWorkOrder.getWorkChain());

                resVo.getGtArray().add(rr);
            }

        }

        res.sort(Comparator.comparing(ApsOrderGanttChartResVo::getStationCode));
        return new BaseListResVo<>(res);
    }

    public BaseListResVo<ApsOrderGanttChartResVo> ganttChart(ApsOrderGanttChartReqVo reqVo) {
        LambdaQueryWrapper<ApsWorkDetail> wrapper = Wrappers.lambdaQuery();

        if(CollUtil.isNotEmpty(reqVo.getGroupIds())){
//            List<StationGroup> stationGroups = stationGroupMapper.selectList(Wrappers.<StationGroup>lambdaQuery().in(StationGroup::getGroupId, reqVo.getGroupIds()));
//            if(CollUtil.isEmpty(stationGroups)){
//                return BaseListResVo.empty();
//            }
//            List<Integer> stationIds = stationGroups.stream().map(StationGroup::getId).distinct().collect(Collectors.toList());
            List<Station> stationList = stationMapper.lambdaQuery().in(Station::getGroupId, reqVo.getGroupIds()).list();
            List<Integer> stationIds = stationList.stream().map(Station::getId).collect(Collectors.toList());
            wrapper.in(ApsWorkDetail::getStationGroupId, stationIds);
        }

        if(reqVo.getPlanStartDateTime() == null){
            reqVo.setPlanStartDateTime(LocalDateTime.now());
        }

        if(reqVo.getPlanEndDateTime() == null){
            reqVo.setPlanEndDateTime(reqVo.getPlanStartDateTime().plusDays(7));
        }

        // 2.查出某个 ApsWorkDetail 下这个时间段内的所有的排产信息
        wrapper.ge(reqVo.getPlanStartDateTime() != null, ApsWorkDetail::getPlanStartDateTime, reqVo.getPlanStartDateTime());
        wrapper.le(reqVo.getPlanEndDateTime() != null, ApsWorkDetail::getPlanEndDateTime, reqVo.getPlanEndDateTime());
        wrapper.eq(reqVo.getOrderId() != null, ApsWorkDetail::getOrderId, reqVo.getOrderId());
        wrapper.eq(reqVo.getApsOrderId() != null, ApsWorkDetail::getApsOrderId, reqVo.getApsOrderId());
        wrapper.in(reqVo.getStationId() != null, ApsWorkDetail::getStationId, reqVo.getStationId());
        wrapper.in(ApsWorkDetail::getStatus, 2, 3);
        wrapper.in(ApsWorkDetail::getOrderType, 1, 3, 4);

        return orderGanttChart(wrapper, 2);
    }

    @Transactional
    public void pubFallback(ApsOrderPublishReqVo reqVo) {

        List<ApsOrder> apsOrders = apsOrderMapper.selectBatchIds(reqVo.getIds());
        for (ApsOrder apsOrder : apsOrders) {
            apsOrder.setOrderStatus(1);
            apsOrderMapper.updateById(apsOrder);

            apsWorkOrderMapper.deleteOrderId(apsOrder.getId());
            apsWorkDetailMapper.deleteOrderId(apsOrder.getId());
            apsDetailWeekdayMapper.deleteOrderId(apsOrder.getId());
        }

    }

    public BaseSelectResVo select() {

        LambdaQueryWrapper<ApsOrder> wrapper = Wrappers.lambdaQuery();
        wrapper.ge(ApsOrder::getOrderStatus, 5);
        List<ApsOrder> apsOrders = apsOrderMapper.selectList(wrapper);

        List<BaseSelectItemResVo> collect = apsOrders.stream()
                .map(e -> {
                    BaseSelectItemResVo resVo = new BaseSelectItemResVo();
                    resVo.setText(e.getOrderCode() + "-" + e.getMaterName() + "-" + PkgUtils.gen(e.getSeq()));
                    resVo.setValue(e.getId());
                    return resVo;
                })
                .collect(Collectors.toList());
        return BaseSelectResVo.of(collect);
    }

    public BaseListResVo<ApsOrderGroupLoadResVo> groupLoad(ApsOrderGroupLoadReqVo reqVo) {

        QueryWrapper<ApsDetailWeekday> wrapper = Wrappers.query();
        wrapper.ge("adw.state", 5);
        wrapper.eq("adw.deleted", 0);
        wrapper.ge("adw.shift_day", reqVo.getStartDate());
        wrapper.le("adw.shift_day", reqVo.getEndDate());
        wrapper.eq(reqVo.getGroupId()!= null, "adw.group_id", reqVo.getGroupId());
        wrapper.groupBy("adw.group_id", "adw.shift_day");
        wrapper.orderByDesc("adw.shift_day");
        wrapper.orderByAsc("g.my_code");

        List<ApsOrderGroupLoadResVo> list = apsDetailWeekdayMapper.selectGroupLoad(wrapper);
        if(list.isEmpty()){
            return BaseListResVo.empty();
        }

        List<Integer> groupIds = list.stream().map(ApsOrderGroupLoadResVo::getGroupId).distinct().collect(Collectors.toList());

//        // 取出工作组下所有的工位
//        List<StationGroup> stationGroups = stationGroupMapper.selectList(Wrappers.<StationGroup>lambdaQuery().eq(StationGroup::getDefaultGroup, 1).in(StationGroup::getGroupId, groupIds));
//        List<Integer> stationIds = stationGroups.stream().map(StationGroup::getStationId).distinct().collect(Collectors.toList());
        List<Station> stationList = stationMapper.lambdaQuery().in(Station::getGroupId, groupIds).list();
        List<Integer> stationIds = stationList.stream().map(Station::getId).collect(Collectors.toList());

        // 取出工位的日历和班制，算出日历的工作时间
        List<StationWeekdayScheme> stationWeekdaySchemes = stationWeekdaySchemeMapper.selectList(Wrappers.<StationWeekdayScheme>lambdaQuery().in(StationWeekdayScheme::getStationId, stationIds));
        List<Integer> shiftTypeIds = stationWeekdaySchemes.stream().map(StationWeekdayScheme::getShiftTypeId).distinct().collect(Collectors.toList());
        List<Shift> shifts = shiftMapper.selectList(Wrappers.<Shift>lambdaQuery().in(Shift::getShiftTypeId, shiftTypeIds));

        Map<Integer, StationWeekdayScheme> stationSchemeMap = stationWeekdaySchemes.stream().collect(Collectors.toMap(StationWeekdayScheme::getStationId, s -> s));
        Map<Integer, List<Shift>> shiftMap = shifts.stream().collect(Collectors.groupingBy(Shift::getShiftTypeId));

        Map<Integer, Integer> groupIdDateMap = new HashMap<>();
        for (Integer stationId : stationIds) {
            StationWeekdayScheme scheme = stationSchemeMap.get(stationId);
            Station station = stationMapper.selectById(stationId);
            Group group = groupMapper.selectById(station.getGroupId());
            if (scheme == null) {
                throw SyExceptionUtils.e("[{}]工作组的[{}]工位日历信息不完整", group.getMyCode(), station.getMyCode());
            }

            if(reqVo.getStartDate().isBefore(scheme.getStartDate()) || reqVo.getEndDate().isAfter(scheme.getEndDate())){
                throw SyExceptionUtils.e("[{}]工作组的[{}]工位时间链超出工位日历范围", group.getMyCode(), station.getMyCode());
            }

            List<Shift> machineShift = shiftMap.get(scheme.getShiftTypeId());
            int sum = machineShift.stream().mapToInt(Shift::getTotalTime).sum();

            Integer i = groupIdDateMap.computeIfAbsent(group.getId(), k -> 0);
            groupIdDateMap.put(group.getId(), i + sum);
        }

        for (ApsOrderGroupLoadResVo vo : list) {
            Integer all = groupIdDateMap.get(vo.getGroupId());
            vo.setTotalWorkTime(all * 60);
            vo.setWorkLoad(new BigDecimal(vo.getUsedWorkTime()).divide(new BigDecimal(all), 2, RoundingMode.HALF_UP));
        }

        return new BaseListResVo<>(list);
    }

    public BaseListResVo<ApsOrderGroupGanttChartResVo> groupGanttChart(ApsOrderGroupGanttChartReqVo reqVo) {


        LambdaQueryWrapper<ApsWorkDetail> wrapper = Wrappers.lambdaQuery();

        wrapper.in(reqVo.getGroupIds() != null, ApsWorkDetail::getGroupId, reqVo.getGroupIds());
        wrapper.eq(reqVo.getApsOrderId() != null, ApsWorkDetail::getApsOrderId, reqVo.getApsOrderId());
        wrapper.ge( ApsWorkDetail::getPlanStartDateTime, reqVo.getPlanStartDateTime());
        wrapper.le( ApsWorkDetail::getPlanEndDateTime, reqVo.getPlanEndDateTime());


        List<ApsWorkDetail> apsWorkDetails = apsWorkDetailMapper.selectList(wrapper);
        if(CollUtil.isEmpty(apsWorkDetails)){
            return BaseListResVo.empty();
        }


        Map<String, List<ApsWorkDetail>> collect = apsWorkDetails.stream().collect(Collectors.groupingBy(ApsWorkDetail::getGroupCode));

        List<Integer> apsOrderIds = apsWorkDetails.stream().map(ApsWorkDetail::getApsOrderId).distinct().collect(Collectors.toList());

        if(CollUtil.isEmpty(apsOrderIds)){
            return BaseListResVo.empty();
        }

        List<ApsOrder> apsOrders = apsOrderMapper.selectBatchIds(apsOrderIds);
        if(CollUtil.isEmpty(apsOrderIds)){
            return BaseListResVo.empty();
        }

        Map<Integer, ApsOrder> apsOrderIdMap = apsOrders.stream().collect(Collectors.toMap(ApsOrder::getId, Function.identity()));

        List<String> colors = Lists.newArrayList("#93E5A0", "#F1A599", "#3D93F6", "#F6AF43", "#6BC471", "#47CBE6", "#9FD2FF", "#B29FFF", "#FFDA61", "#FF7F50", "#FFD299", "#8FBF9F");
        Map<Integer, String> subOrderIdMap = new HashMap<>();

        List<ApsOrderGroupGanttChartResVo> res = new ArrayList<>();
        for (Map.Entry<String, List<ApsWorkDetail>> entry : collect.entrySet()) {
            ApsOrderGroupGanttChartResVo resVo = new ApsOrderGroupGanttChartResVo();
            resVo.setStationCode(entry.getKey());

            res.add(resVo);
            List<ApsWorkDetail> details = entry.getValue();
            for (ApsWorkDetail detail : details) {
                ApsOrderGanttChartArrayResVo rr = new ApsOrderGanttChartArrayResVo();
                rr.setStart(detail.getPlanStartDateTime());
                rr.setEnd(detail.getPlanEndDateTime());

                rr.setConstructNo(apsOrderIdMap.get(detail.getApsOrderId()).getConstructNo());
                rr.setOrderCode(apsOrderIdMap.get(detail.getApsOrderId()).getOrderCode());
                rr.setSeq(PkgUtils.gen(apsOrderIdMap.get(detail.getApsOrderId()).getSeq()));

                rr.setApsOrderId(detail.getApsOrderId());
                rr.setPhaseCode(detail.getPhaseCode());
                rr.setPhaseName(detail.getPhaseName());
                rr.setBomName(detail.getMaterName());
                rr.setBomCode(detail.getMaterNo());
                rr.setCount(detail.getTotalCount());
                rr.setPlmId(rr.getBomCode());
                rr.setWorkTimeMinutes(new BigDecimal(detail.getWorkTime()).divide(new BigDecimal(60), 2, RoundingMode.HALF_UP));
                rr.setPlanTimeMinutes(new BigDecimal(detail.getTotalWorkTime()).divide(new BigDecimal(60), 2, RoundingMode.HALF_UP));

                // 取出所有的订单，给订单去重，并给订单配上颜色
                String s = subOrderIdMap.computeIfAbsent(rr.getApsOrderId(), k -> colors.get(subOrderIdMap.size() % colors.size()));
                rr.setColor(s);


                rr.setGroupCode(detail.getGroupCode());
                resVo.getGtArray().add(rr);
            }

        }

        res.sort(Comparator.comparing(ApsOrderGroupGanttChartResVo::getStationCode));
        return new BaseListResVo<>(res);
    }

    public BaseSelectResVo subOrder(BaseIdReqVo reqVo) {
        LambdaQueryWrapper<ApsOrder> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(ApsOrder::getOrderId, reqVo.getId());
        wrapper.ge(ApsOrder::getOrderStatus, 5);
        wrapper.orderByAsc(ApsOrder::getSeq);
        List<ApsOrder> apsOrders = apsOrderMapper.selectList(wrapper);
        List<BaseSelectItemResVo> collect = apsOrders.stream()
                .map(e -> {
                    BaseSelectItemResVo rr = new BaseSelectItemResVo();
                    rr.setText(PkgUtils.gen(e.getSeq()));
                    rr.setValue(e.getId());
                    return rr;
                })
                .collect(Collectors.toList());
        return BaseSelectResVo.of(collect);
    }

    @Transactional
    public void clear(List<Integer> apsOrderIds) {

        List<ApsOrder> apsOrders = apsOrderMapper.selectBatchIds(apsOrderIds.stream().distinct().collect(Collectors.toList()));

        Map<Integer, List<ApsOrder>> orderMap = apsOrders.stream().collect(Collectors.groupingBy(ApsOrder::getOrderId));

        for (Map.Entry<Integer, List<ApsOrder>> entry : orderMap.entrySet()) {

            LambdaUpdateWrapper<ApsOrder> wr = Wrappers.lambdaUpdate();
//            wr.set(ApsOrder::getOrderStatus, 3);
            wr.set(ApsOrder::getPlanStartDateTime, null);
            wr.set(ApsOrder::getPlanEndDateTime, null);
            wr.in(ApsOrder::getId, entry.getValue().stream().map(BaseEntity::getId).collect(Collectors.toList()));
            apsOrderMapper.update(null, wr);
            apsWorkOrderMapper.deleteOrderId(entry.getKey());
            apsWorkDetailMapper.deleteOrderId(entry.getKey());
            apsDetailWeekdayMapper.deleteOrderId(entry.getKey());
        }

    }

    @Transactional
    public void afterScheduleClear(List<ApsBatch> apsBatchList) {
        List<Order> orderList = orderMapper.selectList(Wrappers.<Order>lambdaQuery().in(Order::getBatchId, apsBatchList.stream().map(BaseEntity::getId).collect(Collectors.toList())));
        if(orderList.isEmpty()){
            return ;
        }

        for (Order order : orderList) {
            order.setOrderStatus(3);
            orderMapper.updateById(order);
        }

        List<ApsOrder> apsOrders = apsOrderMapper.selectList(Wrappers.<ApsOrder>lambdaQuery().in(ApsOrder::getOrderId, orderList.stream().map(BaseEntity::getId).collect(Collectors.toList())));

        Map<Integer, List<ApsOrder>> orderMap = apsOrders.stream().collect(Collectors.groupingBy(ApsOrder::getOrderId));

        for (Map.Entry<Integer, List<ApsOrder>> entry : orderMap.entrySet()) {

            LambdaUpdateWrapper<ApsOrder> wr = Wrappers.lambdaUpdate();
            wr.set(ApsOrder::getOrderStatus, 3);
            wr.set(ApsOrder::getPlanStartDateTime, null);
            wr.set(ApsOrder::getPlanEndDateTime, null);
            wr.in(ApsOrder::getId, entry.getValue().stream().map(BaseEntity::getId).collect(Collectors.toList()));


            apsOrderMapper.update(null, wr);
            apsWorkOrderMapper.deleteOrderId(entry.getKey());
            apsWorkDetailMapper.deleteOrderId(entry.getKey());
            apsDetailWeekdayMapper.deleteOrderId(entry.getKey());
        }

    }


    public BaseListResVo<ApsOrderCurrentWorkDetailResVo> currentWorkDetail(BaseIdReqVo reqVo) {

        ApsWorkDetail apsWorkDetail = apsWorkDetailMapper.selectById(reqVo.getId());

        List<ApsWorkDetail> list = apsWorkDetailMapper.lambdaQuery()
                .eq(ApsWorkDetail::getApsWorkOrderId, apsWorkDetail.getApsWorkOrderId())
                .list();


        return BaseListResVo.of(list, ApsOrderCurrentWorkDetailResVo.class);
    }

    @Transactional(rollbackFor = Exception.class)
    public ApsBatch scheduleReorder(ApsOrderScheduleReqVo reqVo, ApsBatch apsBatch) {

        List<ApsOrder> apsOrders = apsOrderMapper.selectBatchIds(reqVo.getIds());

        // 2.数据校验
        valid(apsOrders, reqVo);

        // 3.子订单排序
        ScheduleRole scheduleRole = strategyConfig.getScheduleRole(reqVo.getSchedulingRule());
        List<ApsOrder> sortOrder = scheduleRole.sort(apsOrders, reqVo);

        // 4.构建工厂缓存信息
        ApsFactoryCache apsFactoryCache = genApsFactoryCache(sortOrder, reqVo);
        apsFactoryCache.setBottleneckPhaseCode(reqVo.getBottleneckPhaseCode());

        List<Integer> orderIds = sortOrder.stream().map(ApsOrder::getOrderId).distinct().collect(Collectors.toList());
        List<Order> orders = orderMapper.selectList(Wrappers.<Order>lambdaQuery().in(Order::getId, orderIds));

        LocalDateTime now = LocalDateTime.now();
        if(apsBatch == null){
            apsBatch = new ApsBatch();
            apsBatch.setBatchNo(now.format(DatePattern.NORM_DATETIME_FORMATTER));
            apsBatch.setSchedulingRule(reqVo.getSchedulingRule());
            apsBatch.setSchedulingDateTime(now);
            apsBatch.setStatus(1);
            apsBatchMapper.insert(apsBatch);
        } else {
            apsBatch.setBatchNo(now.format(DatePattern.NORM_DATETIME_FORMATTER));
            apsBatch.setSchedulingDateTime(now);
            apsBatchMapper.updateById(apsBatch);
        }


        for (Order order : orders) {
            order.setPlanStartDateTime(null);
            order.setPlanEndDateTime(null);
            order.setBatchId(apsBatch.getId());
            orderMapper.updateById(order);
        }
        Map<Integer, Order> orderIdMap = orders.stream().collect(Collectors.toMap(Order::getId, Function.identity()));


        for (ApsOrder apsOrder : sortOrder) {

            // 构建订单缓存信息，包含所有的订单
            ApsOrderCache apsOrderCache = genApsOrderCacheReorder(apsFactoryCache, orderIdMap.get(apsOrder.getOrderId()), apsOrder, reqVo);

            // 排产所有工序
            ApsAlgorithm apsAlgorithm = strategyConfig.getApsAlgorithm(ApsAlgorithm.APS_FORWARD_SCHEDULING_CODE);
            apsAlgorithm.scheduleTask(apsFactoryCache, apsOrderCache);


            if (CollUtil.isNotEmpty(apsFactoryCache.getBottleneckPhaseCode())) {
                ApsAlgorithm apsAlgorithm1 = strategyConfig.getApsAlgorithm(ApsAlgorithm.APS_BOTTLENECK_ALGORITHM_CODE);
                apsAlgorithm1.scheduleTask(apsFactoryCache, apsOrderCache);
            }


            // 排产外购件
            apsAlgorithm.scheduleWl(apsFactoryCache, apsOrderCache);


            LocalDateTime planStartDateTime = apsOrderCache.getWorkOrders().stream().filter(e->e.getPlanStartDateTime() != null).min(Comparator.comparing(ApsWorkOrder::getPlanStartDateTime)).orElseThrow(() -> SyExceptionUtils.e("没有找到排产的工单")).getPlanStartDateTime();
            apsOrder.setPlanStartDateTime(planStartDateTime);

            LocalDateTime planEndDateTime = apsOrderCache.getWorkOrders().stream().filter(e->e.getPlanEndDateTime() != null).max(Comparator.comparing(ApsWorkOrder::getPlanStartDateTime)).orElseThrow(() -> SyExceptionUtils.e("没有找到排产的工单")).getPlanEndDateTime();
            apsOrder.setPlanEndDateTime(planEndDateTime);

            apsOrder.setOrderStatus(5);
            apsOrder.setLocked(2);
            apsOrderMapper.updateById(apsOrder);

            Order order = orderIdMap.get(apsOrder.getOrderId());

            order.setOrderStatus(apsOrder.getOrderStatus());
            if(order.getPlanStartDateTime() == null){
                order.setPlanStartDateTime(apsOrder.getPlanStartDateTime());
                order.setPlanEndDateTime(apsOrder.getPlanEndDateTime());
            } else {
                if(apsOrder.getPlanStartDateTime().isBefore(order.getPlanStartDateTime())){
                    order.setPlanStartDateTime(apsOrder.getPlanStartDateTime());
                }
                if(apsOrder.getPlanEndDateTime().isAfter(order.getPlanEndDateTime())){
                    order.setPlanEndDateTime(apsOrder.getPlanEndDateTime());
                }
            }

            orderMapper.updateById(order);

        }

        return apsBatch;

    }


    public ApsOrderCache genApsOrderCacheReorder(ApsFactoryCache apsFactoryCache, Order order, ApsOrder apsOrder, ApsOrderScheduleReqVo reqVo) {

        ApsOrderCache cache = new ApsOrderCache();

        cache.setOrder(order);
        cache.setApsOrder(apsOrder);
        cache.setStartDateTime(reqVo.getStartDateTime());

        List<OrderBom> orderBoms = orderBomMapper.lambdaQuery().eq(OrderBom::getOrderId, order.getId()).list();
        cache.setOrderBoms(orderBoms);

        List<OrderPhase> orderPhases = orderPhaseMapper.lambdaQuery().eq(OrderPhase::getOrderId, order.getId()).list();
        cache.setOrderPhases(orderPhases);


        List<ApsWorkOrder> apsBoms = apsWorkOrderMapper.lambdaQuery()
                .eq(ApsWorkOrder::getApsOrderId, apsOrder.getId())
                .eq(ApsWorkOrder::getOrderId, order.getId())
                .list();
        cache.setWorkOrders(apsBoms);

        List<ApsWorkDetail> collect = apsWorkDetailMapper.lambdaQuery()
                .eq(ApsWorkDetail::getApsOrderId, apsOrder.getId())
                .eq(ApsWorkDetail::getOrderId, order.getId())
                .orderByAsc(ApsWorkDetail::getId)
                .list();

        List<ApsTask> tasks = collect.stream()
                .map(e -> {
                    ApsTask t = new ApsTask(e);
                    t.setConsumerStatus(1);
                    t.setConsumerCount(new BigDecimal(0));
                    return t;
                })
                .sorted(Comparator.comparing(t -> t.getApsWorkDetail().getDetailSeq()))
                .collect(Collectors.toList());
        cache.setTaskList(tasks);


        Map<Integer, Map<Integer, List<ApsTask>>> workOrderIdPhaseSeqMap = tasks.stream().collect(Collectors.groupingBy(ApsTask::getApsWorkOrderId, Collectors.groupingBy(ApsTask::getPhaseSeq)));
        cache.setWorkOrderIdPhaseSeqMap(workOrderIdPhaseSeqMap);

        Map<Integer, List<ApsTask>> workOrderPidMap = tasks.stream().filter(e -> e.getApsWorkOrderPid() != null).collect(Collectors.groupingBy(ApsTask::getApsWorkOrderPid));
        cache.setWorkOrderPidMap(workOrderPidMap);

        return cache;
    }

    @Transactional
    public void clearApsDetailWeekday(List<Integer> orderIdList) {

        // 设置状态为 -1
        for (Integer orderId : orderIdList) {
            List<ApsWorkDetail> todoWorkDetailList = apsWorkDetailMapper.lambdaQuery()
                    .eq(ApsWorkDetail::getOrderId, orderId)
                    .eq(ApsWorkDetail::getType, 2)
                    .lt(ApsWorkDetail::getFinishCount, "0.05")
//                    .eq(ApsWorkDetail::getStatus, 2)
                    .list();

            List<Integer> workDetailIdList = todoWorkDetailList.stream()
                    .map(BaseEntity::getId)
                    .collect(Collectors.toList());

            QueryWrapper<ApsDetailWeekday> query = Wrappers.query();
            query.eq("order_id", orderId);
            query.in("aps_work_detail_id", workDetailIdList);
            apsDetailWeekdayMapper.deleteByApsWorkDetailId(query);

            apsWorkDetailMapper.lambdaUpdate()
                    .set(ApsWorkDetail::getStatus, -1)
                    .in(ApsWorkDetail::getId, workDetailIdList)
                    .update();

        }

    }

    @Transactional
    public void reorder(OrderReorderReqVo reqVo2, Map<ApsBatch, List<Order>> reorder) {
        List<Integer> orderIdList = reorder.values().stream().flatMap(List::stream).map(BaseEntity::getId).distinct().collect(Collectors.toList());

        // 清理订单 清除 status为2，并且adw = 1的数据
        clearApsDetailWeekday(orderIdList);

        for (Map.Entry<ApsBatch, List<Order>> entry : reorder.entrySet()) {
            List<ApsOrder> schedule = apsOrders(entry.getKey(), entry.getValue());

            ApsOrderScheduleReqVo reqVo1 = new ApsOrderScheduleReqVo();
            reqVo1.setIds(schedule.stream().map(BaseEntity::getId).collect(Collectors.toList()));
            reqVo1.setSchedulingRule(entry.getKey().getSchedulingRule());
            reqVo1.setStartDateTime(reqVo2.getStartDateTime());
            reqVo1.setPreview(false);
            reqVo1.setBottleneckPhaseCode(WorkshopProp.BOTTLENECK_PHASE_CODE);
            try {

                // 锁定
                lock(reqVo1);

                // 排产
//                apsOrderService.schedule(reqVo1, entry.getKey());
                scheduleReorder(reqVo1, entry.getKey());

                // 如果抛异常，则给未排产的解锁
                unlock(reqVo1, 5);

                publish(entry.getKey());


            } catch (Exception e) {

                // 如果抛异常，则给未排产的解锁
                unlock(reqVo1, 3);

                // 清理订单
                clear(reqVo1.getIds());

                log.error(e.getMessage(), e);

                throw e;
            }

        }
    }

    public void publish(ApsBatch apsBatch) {

        List<ApsOrder> apsOrders = apsOrderMapper.selectList(Wrappers.<ApsOrder>lambdaQuery()
                .eq(ApsOrder::getOrderStatus, 5)
        );

        if(CollUtil.isEmpty(apsOrders)){
            throw SyExceptionUtils.e("没有找到已排产的数据");
        }

        List<Integer> collect = apsOrders.stream().map(ApsOrder::getOrderId).collect(Collectors.toList());

        orderMapper.update(null, Wrappers.<Order>lambdaUpdate()
                .set(Order::getOrderStatus, 6)
                .set(Order::getPushStatus, 1)
                .set(Order::getLocked, 2)
                .in(Order::getId, collect)
        );

        List<Integer> apsIds = apsOrders.stream().map(BaseEntity::getId).collect(Collectors.toList());

        apsOrderMapper.update(null, Wrappers.<ApsOrder>lambdaUpdate()
                .set(ApsOrder::getOrderStatus, 6)
                .set(ApsOrder::getLocked, 2)
                .in(BaseEntity::getId, apsIds)
        );

        // 更新apsWorkOrder
        apsWorkOrderMapper.update(null, Wrappers.<ApsWorkOrder>lambdaUpdate()
                .set(ApsWorkOrder::getStatus, 2)
                .in(ApsWorkOrder::getApsOrderId, apsIds)
        );
        // 更新apsWorkDetailMapper
        apsWorkDetailMapper.update(null, Wrappers.<ApsWorkDetail>lambdaUpdate()
                .set(ApsWorkDetail::getStatus, 2)
                .in(ApsWorkDetail::getApsOrderId, apsIds)
        );
        // 更新apsDetailWeekdayMapper
        apsDetailWeekdayMapper.update(null, Wrappers.<ApsDetailWeekday>lambdaUpdate()
                .set(ApsDetailWeekday::getState, 2)
                .in(ApsDetailWeekday::getApsOrderId, apsIds)
        );


        apsBatch.setStatus(2);
        apsBatchMapper.updateById(apsBatch);

        apsBatchMapper.deleteNoPub(apsBatch.getId());

    }

    public List<ApsOrder> apsOrders(ApsBatch apsBatch, List<Order> orders) {
        if(CollUtil.isEmpty(orders)){
            throw SyExceptionUtils.e("没有待排产的订单");
        }

        List<Integer> orderIds = orders.stream().map(BaseEntity::getId).collect(Collectors.toList());


        // 对apsOrders进行分组排序
        return apsOrderMapper.lambdaQuery()
                .in(ApsOrder::getOrderId, orderIds)
                .in(ApsOrder::getOrderType, 1, 3, 4)
                .list();

    }

    public List<OrderSubOrderResVo> subList(BaseIdReqVo reqVo) {

        List<ReverseOrder> list = reverseOrderMapper.lambdaQuery()
                .eq(ReverseOrder::getOrderId, reqVo.getId())
                .isNotNull(ReverseOrder::getParentId)
                .orderByAsc(ReverseOrder::getSplitNum)
                .list();

        return list.stream()
                .map(e -> {
                    OrderSubOrderResVo rr = new OrderSubOrderResVo();
                    rr.setPkgCode(PkgUtils.gen(e.getSplitNum()));
                    rr.setTotal(e.getOrderQty());
                    rr.setId(e.getId());
                    rr.setStartDate(e.getDeliveryDate());
                    return rr;
                })
                .collect(Collectors.toList());
    }

    @Transactional(readOnly = true)
    public Map<ApsBatch, List<Order>> findApsBatch(ApsOrderScheduleReqVo reqVo) {

        // 找到待排产的工单详情
        List<ApsWorkDetail> todoWorkDetailList = apsWorkDetailMapper.lambdaQuery().eq(ApsWorkDetail::getStatus, 2).list();

        // 找到工单详情涉及到的订单
        List<Integer> orderIdList = todoWorkDetailList.stream().map(ApsWorkDetail::getOrderId).distinct().collect(Collectors.toList());
        List<Order> orderList = orderMapper.selectBatchIds(orderIdList);

        // 找到订单的批次
        Map<ApsBatch, List<Order>> map = new LinkedHashMap<>();

        List<Integer> batchIdList = orderList.stream().map(Order::getBatchId).distinct().collect(Collectors.toList());

        List<ApsBatch> batchList = apsBatchMapper.selectBatchIds(batchIdList);
        //
        batchList = apsBatchMapper.lambdaQuery()
                .in(ApsBatch::getId, 106, 111, 124)
                .list();

        if (CollUtil.isEmpty(batchList)) {
            return map;
        }

        ApsBatch minBatch = batchList.stream().min(Comparator.comparing(ApsBatch::getSchedulingDateTime)).orElseThrow(() -> SyExceptionUtils.e("没有待排产的订单"));

        // 找到比这个大的所有批次
        List<ApsBatch> allBatchList = apsBatchMapper.lambdaQuery().ge(ApsBatch::getSchedulingDateTime, minBatch.getSchedulingDateTime()).list();
        allBatchList = batchList;
        List<Integer> collect = allBatchList.stream().map(BaseEntity::getId).collect(Collectors.toList());
        List<Order> allOrderList = orderMapper.lambdaQuery().in(Order::getBatchId, collect).in(Order::getOrderType, 1, 3, 4).list();
        Map<Integer, List<Order>> batchIdMap = allOrderList.stream().collect(Collectors.groupingBy(Order::getBatchId));

        for (ApsBatch apsBatch : allBatchList) {
            List<Order> orders = batchIdMap.get(apsBatch.getId());
            orders.sort(Comparator.comparing(Order::getSeq));
            map.put(apsBatch, orders);
        }

        return map;
    }

    @Transactional
    public void reScheduling(ApsOrderScheduleReqVo reqVo1, Map<ApsBatch, List<Order>> apsBatchListMap) {
        List<Integer> orderIdList = apsBatchListMap.values().stream().flatMap(List::stream).map(BaseEntity::getId).distinct().collect(Collectors.toList());

        // 检查redis是否有锁定状态，如果有则提示，并且不排产
        ValueOperations<String, String> valOperation = stringRedisTemplate.opsForValue();
        stringRedisTemplate.delete(ApsConstant.APS_SCHEDULING_LOCK);


        String lockFlag = valOperation.get(ApsConstant.APS_SCHEDULING_LOCK);
        if (StringUtils.hasText(lockFlag)) {
            throw SyExceptionUtils.e("{} 等订单排产中!", lockFlag);
        }

        // 清理订单 清除 status为2，并且adw = 1的数据
        clearApsDetailWeekday(orderIdList);

        // 3.把待排产的订单号放入redis，设置锁定状态
//        valOperation.set(ApsConstant.APS_SCHEDULING_LOCK, "重排中", 1, TimeUnit.DAYS);

        for (Map.Entry<ApsBatch, List<Order>> apsBatchEntry : apsBatchListMap.entrySet()) {
            log.info("scheduling reqVo: {}", reqVo1.getSchedulingRule());

            ApsSchedulingOrderCacheBo orderCache = new ApsSchedulingOrderCacheBo();
            orderCache.setStartDateTime(reqVo1.getAssemblyStartDateTime());

            // 取出待排产的订单
            List<Order> orderList = apsBatchEntry.getValue();

            // 取出所有待排产的订单
            if (CollUtil.isEmpty(orderList)) {
                continue;
            }

            orderCache.setOrderList(orderList);
            orderCache.setSchedulingRule(reqVo1.getSchedulingRule());

            List<Integer> orderIds = orderList.stream().map(BaseEntity::getId).collect(Collectors.toList());

            // 取aps
            List<ApsOrder> apsOrderList = apsOrderMapper.lambdaQuery()
                    .in(ApsOrder::getOrderId, orderIds)
                    .in(ApsOrder::getOrderType, 1, 3, 4)
                    .list();
            orderCache.setApsOrderList(apsOrderList);

            // 1.准备批次数据
            ApsBatch apsBatch = apsBatchEntry.getKey();
            modifyBatch(apsBatch, reqVo1);
            apsBatchMapper.updateById(apsBatch);
            orderCache.setApsBatch(apsBatch);

            List<Integer> apsOrderIds = orderCache.getApsOrderList().stream().map(BaseEntity::getId).collect(Collectors.toList());
            apsOrderMapper.lambdaUpdate()
                    .set(ApsOrder::getOrderStatus, 4)
                    .in(ApsOrder::getId, apsOrderIds)
                    .update();

            // 转换MAP属于多此一举
            Map<Integer, List<ApsOrder>> orderMap = apsOrderList.stream().collect(Collectors.groupingBy(ApsOrder::getOrderId));
            for (Map.Entry<Integer, List<ApsOrder>> entry : orderMap.entrySet()) {
                LambdaUpdateWrapper<ApsOrder> wr = Wrappers.lambdaUpdate();
                wr.set(ApsOrder::getPlanStartDateTime, null);
                wr.set(ApsOrder::getPlanEndDateTime, null);
                wr.in(ApsOrder::getId, entry.getValue().stream().map(BaseEntity::getId).collect(Collectors.toList()));
                apsOrderMapper.update(null, wr);
//                apsWorkOrderMapper.deleteOrderId(entry.getKey());
//                apsWorkDetailMapper.deleteOrderId(entry.getKey());
//                apsDetailWeekdayMapper.deleteOrderId(entry.getKey());
            }

            ApsSchedulingFactoryCacheBo factoryCache = new ApsSchedulingFactoryCacheBo();
            factoryCache.setAssemblyStartDateTime(reqVo1.getAssemblyStartDateTime());

            initFactoryCache(factoryCache, orderCache);

            // 给所有的排产
            LocalDateTime now = LocalDateTime.now();
            orderCache.getApsBatch().setStatus(1);
            orderCache.getApsBatch().setBatchNo(now.format(DatePattern.NORM_DATETIME_FORMATTER));
            orderCache.getApsBatch().setSchedulingDateTime(now);
            apsBatchMapper.updateById(apsBatch);

            for (Order order : orderCache.getOrderList()) {
                order.setPlanStartDateTime(null);
                order.setPlanEndDateTime(null);
                order.setBatchId(apsBatch.getId());
                orderMapper.updateById(order);
            }

            initOrderCache(orderCache, factoryCache);

            scheduleTask(orderCache, factoryCache);

            scheduleWl(orderCache, factoryCache);

            saveAndUpate(orderCache);

            System.out.println("--------------");
        }
        throw new RuntimeException("测试异常");
    }

    public void saveAndUpate(ApsSchedulingOrderCacheBo orderCache) {

        // 保存所有的workOrder
//        List<ApsWorkOrderTemp> collect = orderCache.getApsWorkOrderTempList().stream().filter(e -> e.getPid() == null).collect(Collectors.toList());
//        Map<Integer, ApsWorkOrderTemp> apsWorkOrderTempIdMap = orderCache.getApsWorkOrderTempIdMap();
//        Map<Integer, List<ApsWorkOrderTemp>> apsWorkOrderTempPidMap = orderCache.getApsWorkOrderTempPidMap();

        for (ApsWorkOrderTemp apsWorkOrderTemp : orderCache.getApsWorkOrderTempList()) {
            ApsWorkOrder apsWorkOrder = apsWorkOrderTemp.getApsWorkOrder();
            ApsWorkOrder awo = new ApsWorkOrder();
            awo.setId(apsWorkOrder.getId());
            awo.setPlanStartDateTime(apsWorkOrder.getPlanStartDateTime());
            awo.setPlanEndDateTime(apsWorkOrder.getPlanEndDateTime());
            apsWorkOrderMapper.updateById(awo);
        }

//        List<ApsWorkOrderTemp> children = new ArrayList<>(collect);
//        while (CollUtil.isNotEmpty(children)) {
//            List<ApsWorkOrder> saveBatch = children.stream()
//                    .map(e -> {
//                        if (e.getPid() != null) {
//                            e.getApsWorkOrder().setPid(apsWorkOrderTempIdMap.get(e.getPid()).getApsWorkOrder().getId());
//                        }
//                        return e.getApsWorkOrder();
//                    })
//                    .collect(Collectors.toList());
//            apsWorkOrderMapper.insertBatch(saveBatch, 1000);
//
//            List<ApsWorkOrderTemp> temp = new ArrayList<>();
//
//            for (ApsWorkOrderTemp child : children) {
//                List<ApsWorkOrderTemp> apsWorkOrderTemps = apsWorkOrderTempPidMap.get(child.getId());
//                if (CollUtil.isNotEmpty(apsWorkOrderTemps)) {
//                    temp.addAll(apsWorkOrderTemps);
//                }
//            }
//
//            children = temp;
//        }

        // 保存所有的workDetail
//        for (ApsTask task : orderCache.getTaskList()) {
//            ApsWorkOrderTemp apsWorkOrderTemp = apsWorkOrderTempIdMap.get(task.getApsWorkOrderId());
//            task.getApsWorkDetailTemp().getApsWorkDetail().setApsWorkOrderId(apsWorkOrderTemp.getApsWorkOrder().getId());
//            task.getApsWorkDetailTemp().getApsWorkDetail().setApsWorkOrderPid(apsWorkOrderTemp.getApsWorkOrder().getPid());
//        }
//        List<ApsWorkDetail> apsWorkDetailList = orderCache.getTaskList().stream().map(ApsTask::getApsWorkDetail).collect(Collectors.toList());
//        apsWorkDetailMapper.insertBatch(apsWorkDetailList, 2000);
        for (ApsTask task : orderCache.getTaskList()) {
            ApsWorkDetail apsWorkDetail = task.getApsWorkDetail();
            ApsWorkDetail awd = new ApsWorkDetail();
            awd.setId(apsWorkDetail.getId());
            awd.setPlanStartDateTime(apsWorkDetail.getPlanStartDateTime());
            awd.setPlanEndDateTime(apsWorkDetail.getPlanEndDateTime());
            apsWorkDetailMapper.updateById(awd);
        }



        // 保存所有的apsDetailWeekday
        for (ApsTask task : orderCache.getTaskList()) {
            for (ApsWeekDayWrap apsWeekDayWrap : task.getAll()) {
                apsWeekDayWrap.setApsWorkOrderId(task.getApsWorkDetail().getApsWorkOrderId());
                apsWeekDayWrap.setApsWorkDetailId(task.getApsWorkDetail().getId());
            }
        }
        List<ApsDetailWeekday> apsDetailWeekdayList = orderCache.getTaskList()
                .stream()
                .flatMap(e -> e.getAll().stream().map(machineCalendar-> {
                    ApsDetailWeekday calendar = new ApsDetailWeekday();

                    calendar.setOrderId(e.getApsWorkDetail().getOrderId());
                    calendar.setApsOrderId(e.getApsWorkDetail().getApsOrderId());
                    calendar.setApsBomId(e.getApsWorkDetail().getApsWorkOrderId());
                    calendar.setPhaseId(e.getApsWorkDetail().getPhaseId());
                    calendar.setPhaseCode(e.getApsWorkDetail().getPhaseCode());
                    calendar.setPhaseName(e.getApsWorkDetail().getPhaseName());
                    calendar.setApsWorkOrderId(e.getApsWorkDetail().getApsWorkOrderId());
                    calendar.setApsWorkDetailId(e.getApsWorkDetail().getId());
                    calendar.setGroupId(e.getApsWorkDetail().getGroupId());

                    calendar.setWorkTime(machineCalendar.getSecond());
                    calendar.setPlanStartDateTime(machineCalendar.getStart());
                    calendar.setPlanEndDateTime(machineCalendar.getEnd());
                    calendar.setShiftId(machineCalendar.getShiftId());
                    calendar.setShiftSeq(machineCalendar.getShiftSeq());
                    calendar.setShiftStartDateTime(machineCalendar.getShiftStartDateTime());
                    calendar.setShiftEndDateTime(machineCalendar.getShiftEndDateTime());
                    calendar.setShiftDay(machineCalendar.getShiftDay());
                    calendar.setStationGroupId(e.getApsWorkDetail().getStationGroupId());
                    calendar.setStationId(e.getApsWorkDetail().getStationId());
                    calendar.setState(1); // 3 已排产
                    calendar.setOrderType(orderCache.getOrderIdMap().get(e.getApsWorkOrder().getOrderId()).getOrderType());
                    return calendar;
                }))
                .collect(Collectors.toList());
        apsDetailWeekdayMapper.insertBatch(apsDetailWeekdayList, 2000);

        // 更新 apsOrder
//        for (ApsOrder apsOrder : orderCache.getApsOrderList()) {
//            apsOrder.setOrderStatus(5);
//        }
//        apsOrderMapper.updateBatchById(orderCache.getApsOrderList(), 500);

        for (ApsOrder apsOrder : orderCache.getApsOrderList()) {
            ApsOrder ao = new ApsOrder();
            ao.setId(apsOrder.getId());
            ao.setPlanStartDateTime(apsOrder.getPlanStartDateTime());
            ao.setPlanEndDateTime(apsOrder.getPlanEndDateTime());
            apsOrderMapper.updateById(ao);
        }

        // 更新 order
//        for (Order order : orderCache.getOrderList()) {
//            order.setOrderStatus(5);
//        }
//        orderMapper.updateBatchById(orderCache.getOrderList(), 100);
        for (Order order : orderCache.getOrderList()) {
            Order o = new Order();
            o.setId(order.getId());
            o.setPlanStartDateTime(order.getPlanStartDateTime());
            o.setPlanEndDateTime(order.getPlanEndDateTime());
            orderMapper.updateById(o);
        }
    }

    public void scheduleWl(ApsSchedulingOrderCacheBo orderCache, ApsSchedulingFactoryCacheBo factoryCache) {
        List<ApsWorkOrderTemp> collect = orderCache.getApsWorkOrderTempList().stream().filter(e -> e.getApsWorkOrder().getWorkChain().equals("WL")).collect(Collectors.toList());
        Map<Integer, ApsWorkOrderTemp> apsWorkOrderMap = orderCache.getApsWorkOrderTempList().stream().collect(Collectors.toMap(e -> e.getId(), Function.identity()));
        for (ApsWorkOrderTemp apsWorkOrderTemp : collect) {
            ApsWorkOrderTemp apsWorkOrderTemp1 = apsWorkOrderMap.get(apsWorkOrderTemp.getPid());
            apsWorkOrderTemp.getApsWorkOrder().setPlanStartDateTime(apsWorkOrderTemp1.getApsWorkOrder().getPlanStartDateTime());
            apsWorkOrderTemp.getApsWorkOrder().setPlanEndDateTime(apsWorkOrderTemp1.getApsWorkOrder().getPlanStartDateTime());
        }

    }
    public void scheduleTask(ApsSchedulingOrderCacheBo orderCache, ApsSchedulingFactoryCacheBo factoryCache) {
        String patter = ".*(P[1-6]_170|PDB_170|-0[12]0[23])$";
        String namePattern = ".*(拼|[左右]侧护板|挡板组件).*";
        // 取P1到P6的工单
        for (ApsTask e : orderCache.getTaskList()) {
            if (e.getApsWorkDetail().getPlmId().matches(patter) || e.getApsWorkDetail().getMaterName().matches(namePattern)) {
                e.setStatus(2);
            } else {
                e.setStatus(1);
            }
        }

        System.out.println("ass: " + orderCache.getTaskList().stream().filter(e -> e.getStatus() == 2).collect(Collectors.toList()).size());
        System.out.println("part: " + orderCache.getTaskList().stream().filter(e -> e.getStatus() == 1).collect(Collectors.toList()).size());
        List<String> assLog = new ArrayList<>();
        List<String> partLog = new ArrayList<>();


        orderCache.getTaskList().sort((e1, e2) -> {
            int cmp = 0;
            if(orderCache.getSchedulingRule().equals(1)){
                cmp = orderCache.getOrderIdMap().get(e1.getApsWorkOrder().getOrderId()).getSeq().compareTo(orderCache.getOrderIdMap().get(e2.getApsWorkOrder().getOrderId()).getSeq());
                if (cmp != 0) {
                    return cmp;
                }
                cmp = e1.getApsWorkOrder().getApsOrderId().compareTo(e2.getApsWorkOrder().getApsOrderId());
                if (cmp != 0) {
                    return cmp;
                }
            } else {

                cmp = orderCache.getApsOrderIdMap().get(e1.getApsWorkOrder().getApsOrderId()).getSeq().compareTo(orderCache.getApsOrderIdMap().get(e2.getApsWorkOrder().getApsOrderId()).getSeq());
                if (cmp != 0) {
                    return cmp;
                }

                cmp = orderCache.getOrderIdMap().get(e1.getApsWorkOrder().getOrderId()).getSeq().compareTo(orderCache.getOrderIdMap().get(e2.getApsWorkOrder().getOrderId()).getSeq());
                if (cmp != 0) {
                    return cmp;
                }
            }


            cmp = e1.getApsWorkOrder().getLevel().compareTo(e2.getApsWorkOrder().getLevel());
            if (cmp != 0) {
                return -cmp;
            }
            cmp = e1.getApsWorkDetail().getPhaseSeq().compareTo(e2.getApsWorkDetail().getPhaseSeq());
            return cmp;
        });

        LocalDateTime start = null;
        Map<Integer, Map<Integer, List<ApsTask>>> idPhaseSeqMap = orderCache.getWorkOrderIdPhaseSeqMap();
        for (ApsTask currentTask : orderCache.getTaskList()) {

            if (currentTask.getStatus() != 2 && currentTask.getStatus() != 4 ) {
                continue;
            }

            start = null;
            List<ApsTask> preTask = null;

            Optional<Integer> max = idPhaseSeqMap.get(currentTask.getApsWorkOrderTemp().getId()).keySet().stream().filter(e -> e < currentTask.getPhaseSeq()).max(Integer::compareTo);
            if (max.isPresent()) {
                preTask = idPhaseSeqMap.get(currentTask.getApsWorkOrderTemp().getId()).get(max.get());
            }

            if (preTask != null && !preTask.isEmpty()) {
                preTask.stream().filter(task -> task.getPlanEndDateTime() == null).findFirst().ifPresent(task -> {
                    throw SyExceptionUtils.e("[{}]的工序[{}]在工序[{}]之前", currentTask.getApsWorkDetail().getMaterName(), currentTask.getApsWorkDetail().getPhaseCode(), task.getApsWorkDetail().getPhaseCode());
                });

                List<ApsTask> tasks = preTask.stream().filter(e -> e.getConsumerStatus().equals(1) || e.getConsumerStatus().equals(2)).sorted(Comparator.comparing(ApsTask::getConsumerStatus).reversed()).collect(Collectors.toList());
                if(tasks.isEmpty()){
                    start = orderCache.getStartDateTime();
                } else {
                    BigDecimal total = tasks.stream().map(e -> e.getApsWorkDetail().getTotalCount()).reduce(BigDecimal::add).orElseThrow(() -> SyExceptionUtils.e("没有找到前一道工序的数量"));
                    if (currentTask.getApsWorkDetail().getTotalCount().compareTo(total) > 0) {
                        throw SyExceptionUtils.e("数量不足");
                    }

                    BigDecimal remainder = currentTask.getApsWorkDetail().getTotalCount();
                    List<ApsTask> newPreTask = new ArrayList<>();
                    for (ApsTask task : tasks) {
                        if (remainder.compareTo(BigDecimal.ZERO) <= 0) {
                            break;
                        }
                        BigDecimal count = task.getApsWorkDetail().getTotalCount();
                        newPreTask.add(task);
                        if (remainder.compareTo(count) > 0) {
                            task.setConsumerStatus(3);
                            remainder = remainder.subtract(count);
                        } else if (remainder.compareTo(count) == 0) {
                            task.setConsumerStatus(3);
                            task.setConsumerCount(task.getConsumerCount().add(remainder));
                            break;
                        } else {
                            task.setConsumerStatus(2);
                            task.setConsumerCount(task.getConsumerCount().add(remainder));
                            remainder = BigDecimal.ZERO;
                        }
                        task.setConsumerCount(task.getConsumerCount().add(remainder));
                    }

                    ApsTask maxPreTask = newPreTask.stream().max(Comparator.comparing(ApsTask::getPlanEndDateTime)).orElseThrow(() -> SyExceptionUtils.e("没有找到前一道工序的时间"));
                    start = maxPreTask.getPlanEndDateTime();
                }

            } else {
                // 1.2 如果没有前一道工序，校验子节点的完成时间
                List<ApsTask> optionalTask = orderCache.getWorkOrderPidMap().getOrDefault(currentTask.getApsWorkOrderId(), new ArrayList<>()).stream().filter(e-> !e.getStatus().equals(1)).collect(Collectors.toList());

                if (CollUtil.isNotEmpty(optionalTask)) {

                    // 判断是否有未完成的子节点，如果有则抛出异常
                    optionalTask.stream().filter(task -> task.getPlanEndDateTime() == null).findFirst().ifPresent(task -> {
                        throw SyExceptionUtils.e("子节点未完成");
                    });

                    // ---- 修复BUG - 开始 ---
                    Map<Integer, List<ApsTask>> childrenNodeMap = optionalTask.stream().collect(Collectors.groupingBy(e->e.getApsWorkOrderTemp().getId()));
                    for (Map.Entry<Integer, List<ApsTask>> entry : childrenNodeMap.entrySet()) {
                        Integer maxPhaseSeq = entry.getValue().stream().map(ApsTask::getPhaseSeq).max(Integer::compare).orElseThrow(() -> SyExceptionUtils.e("没有找到最大工序"));
                        List<ApsTask> maxPhaseSeqList = entry.getValue().stream().filter(e -> e.getApsWorkDetail().getPhaseSeq().equals(maxPhaseSeq)).filter(e -> e.getConsumerStatus().equals(1) || e.getConsumerStatus().equals(2)).sorted(Comparator.comparing(ApsTask::getConsumerStatus).reversed()).collect(Collectors.toList());
                        if(maxPhaseSeqList.size() == 0){
                            start = orderCache.getStartDateTime();
                        } else {
                            BigDecimal total = maxPhaseSeqList.stream().map(e -> e.getApsWorkDetail().getTotalCount()).reduce(BigDecimal::add).orElseThrow(() ->
                                    SyExceptionUtils.e("没有找到前一道工序的数量")
                            );
                            BigDecimal consumerCount = maxPhaseSeqList.stream().map(ApsTask::getConsumerCount).reduce(BigDecimal::add).orElseThrow(() -> SyExceptionUtils.e("没有找到前一道工序的数量"));
                            BigDecimal parentTotalCount = currentTask.getApsWorkDetail().getTotalCount();
                            BigDecimal partCount = orderCache.getApsWorkOrderTempIdMap().get(maxPhaseSeqList.get(0).getApsWorkOrderId()).getApsWorkOrder().getPartCount();
                            BigDecimal sourceTotal = total.subtract(consumerCount);
                            BigDecimal koujianTotal = parentTotalCount.multiply(partCount);
                            BigDecimal remainder = sourceTotal.subtract(koujianTotal);

//                        System.out.println(String.format("总数量: %s, 已消耗: %s, 父节点数量: %s, 单件数量: %s,需求数: %s, 剩余数: %s", total, consumerCount, parentTotalCount, partCount, koujianTotal, sourceTotal));

                            if (remainder.compareTo(BigDecimal.ZERO) < 0) {
                                throw SyExceptionUtils.e("数量不足");
//                            break;
                            }

                            remainder = koujianTotal;

                            List<ApsTask> newPreTask = new ArrayList<>();
                            for (ApsTask task : maxPhaseSeqList) {
                                BigDecimal count = task.getApsWorkDetail().getTotalCount().subtract(task.getConsumerCount());
                                newPreTask.add(task);
                                if (remainder.compareTo(count) > 0) {
                                    task.setConsumerStatus(3);
                                    remainder = remainder.subtract(count);
                                    task.setConsumerCount(task.getConsumerCount().add(count));
                                } else if (remainder.compareTo(count) == 0) {
                                    task.setConsumerStatus(3);
                                    remainder = remainder.subtract(count);
                                    task.setConsumerCount(task.getConsumerCount().add(count));
                                } else {
                                    task.setConsumerStatus(2);
                                    task.setConsumerCount(task.getConsumerCount().add(remainder));
                                    remainder = BigDecimal.ZERO;
                                }

                                if (remainder.compareTo(BigDecimal.ZERO) == 0) {
                                    break;
                                }
                            }

                            // 之后取子节点的最大结束时间作为开始时间
                            ApsTask task = newPreTask.stream().max(Comparator.comparing(ApsTask::getEndTime)).orElseThrow(() -> SyExceptionUtils.e("没有找到最大的子节点时间"));
                            if(start == null || start.isBefore(task.getEndTime())){
                                start = task.getEndTime();
                            }
                        }


                    }

                } else {
                    start = orderCache.getStartDateTime();
                }
            }


            // 2.找工序对应的设备列表
            List<ApsMachine> machines = factoryCache.getGroupCodeMachineMap().get(currentTask.getGroupCode());
            if (CollUtil.isEmpty(machines)) {
                throw SyExceptionUtils.e("没有找到工作组:[" + currentTask.getGroupCode() + "], 对应的工序:[" + currentTask.getPhaseCode() + "]");
            }


            // 3.把此工序在该列表中依次排产
            List<ApsDetailWeekdayWrap> l = new ArrayList<>();
            for (ApsMachine machine : machines) {
                if (start == null) {
                    start = orderCache.getStartDateTime();
                }

//                if(currentTask.getPhaseCode().equals(apsFactoryCache.getPzCode())){
//                    start = start.plusSeconds(apsFactoryCache.getPzSecond());
//                }

                if (start.isBefore(factoryCache.getAssemblyStartDateTime())) {
                    start = factoryCache.getAssemblyStartDateTime();
                }

                ApsDetailWeekdayWrap scheduling = ApsTaskUtils.scheduling(factoryCache, orderCache, start, machine, currentTask, apsDetailWeekdayMapper, apsWorkDetailMapper, l);
//                ApsDetailWeekdayWrap scheduling = ApsUtils.scheduling(apsFactoryCache, apsOrderCache, start, machine, currentTask, apsDetailWeekdayMapper, apsWorkDetailMapper);
                l.add(scheduling);
            }

            // 4.取出时间最靠前的一次排产结果
            ApsDetailWeekdayWrap calendarWrap = l.stream().min(Comparator.comparing(ApsDetailWeekdayWrap::getStartDateTime)).orElseThrow(() -> SyExceptionUtils.e("排产异常"));
            currentTask.getApsWorkDetail().setPlanStartDateTime(calendarWrap.getStartDateTime());
            currentTask.getApsWorkDetail().setPlanEndDateTime(calendarWrap.getEndDateTime());
            currentTask.setNextTask(calendarWrap.getNext());
            calendarWrap.getPrevious().setNextTask(currentTask);
            currentTask.getApsWorkDetail().setStationId(calendarWrap.getMachine().getId());
            currentTask.setStartMachineCalendar(calendarWrap.getStartMachineCalendar());
            currentTask.setAll(calendarWrap.getAll());
            currentTask.getApsWorkDetail().setStatus(2);
            currentTask.setStatus(5);

            assLog.add(String.format("包号:%s, 零件名称:%s, PLMID:%s, 工序:%s, 开始时间:%s, 结束时间:%s, 工位:%s, 工作组:%s, 数量:%s, 工位数量:%s",
                    PkgUtils.gen(orderCache.getApsOrderIdMap().get(currentTask.getApsWorkDetail().getApsOrderId()).getSeq()),
                    currentTask.getApsWorkDetail().getMaterName(),
                    currentTask.getApsWorkDetail().getPlmId(),
                    currentTask.getApsWorkDetail().getPhaseCode(),
                    currentTask.getApsWorkDetail().getPlanStartDateTime().format(DatePattern.NORM_DATETIME_FORMATTER),
                    currentTask.getApsWorkDetail().getPlanEndDateTime().format(DatePattern.NORM_DATETIME_FORMATTER),
                    currentTask.getApsWorkDetail().getStationId(),
                    currentTask.getApsWorkDetail().getGroupCode(),
                    currentTask.getApsWorkDetail().getTotalCount().intValue(),
                    machines.size()
            ));

        }

        try {
            FileUtils.writeLines(new File("/home/apslog/assLog.txt"), assLog);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }


        // --------开始进行零件排产--------
        for (ApsTask task : orderCache.getTaskList()) {
            if (task.getStatus().equals(1)) {
                task.setStatus(2);
            }
        }

        Map<Integer, Order> orderIdMap = orderCache.getOrderIdMap();
        Map<Integer, ApsOrder> apsOrderIdMap = orderCache.getApsOrderIdMap();
        Map<Integer, Map<Integer, ReverseDetail>> reverseDetailOrderIdPhaseIdMap = orderCache.getReverseDetailOrderIdPhaseIdMap();

        List<ApsTask> collect = orderCache.getTaskList()
                .stream()
                .sorted((e1, e2) -> {

                    int comp = 0;
                    if(orderCache.getSchedulingRule().equals(1)){
                        comp = orderCache.getOrderIdMap().get(e1.getApsWorkOrder().getOrderId()).getSeq().compareTo(orderCache.getOrderIdMap().get(e2.getApsWorkOrder().getOrderId()).getSeq());
                        if (comp != 0) {
                            return - comp;
                        }
                        comp = orderIdMap.get(e1.getApsWorkOrder().getOrderId()).getSeq().compareTo(orderIdMap.get(e2.getApsWorkOrder().getOrderId()).getSeq());
                        if (comp != 0) {
                            return - comp;
                        }
                    } else {
                        comp = orderIdMap.get(e1.getApsWorkOrder().getOrderId()).getSeq().compareTo(orderIdMap.get(e2.getApsWorkOrder().getOrderId()).getSeq());
                        if (comp != 0) {
                            return - comp;
                        }
                        comp = orderCache.getOrderIdMap().get(e1.getApsWorkOrder().getOrderId()).getSeq().compareTo(orderCache.getOrderIdMap().get(e2.getApsWorkOrder().getOrderId()).getSeq());
                        if (comp != 0) {
                            return - comp;
                        }
                    }

                    comp = apsOrderIdMap.get(e1.getApsWorkOrder().getApsOrderId()).getSeq().compareTo(apsOrderIdMap.get(e2.getApsWorkOrder().getApsOrderId()).getSeq());
                    if (comp != 0) {
                        return - comp;
                    }

                    ReverseDetail reverseDetail1 = reverseDetailOrderIdPhaseIdMap.get(e1.getApsWorkOrder().getOrderId()).get(e1.getApsWorkDetail().getPhaseId());
                    ReverseDetail reverseDetail2 = reverseDetailOrderIdPhaseIdMap.get(e2.getApsWorkOrder().getOrderId()).get(e2.getApsWorkDetail().getPhaseId());

                    comp = reverseDetail1.getReverseStartTime().compareTo(reverseDetail2.getReverseStartTime());
                    if (comp != 0) {
                        return - comp;
                    }

                    comp = reverseDetail1.getLevel().compareTo(reverseDetail2.getLevel());
                    if (comp != 0) {
                        return - comp;
                    }

                    if(reverseDetail1.getBomId().compareTo(reverseDetail2.getBomId()) == 0){
                        return - reverseDetail1.getPhaseSeq().compareTo(reverseDetail2.getPhaseSeq());
                    }
                    return - reverseDetail1.getId().compareTo(reverseDetail2.getId());
                })
                .collect(Collectors.toList());



        Map<Integer, Map<Integer, List<ApsTask>>> workOrderIdPhaseSeqMap = orderCache.getWorkOrderIdPhaseSeqMap();
        Map<Integer, Map<Integer, Queue<LocalDateTime>>> parentLastPhaseStartDateTimeMap = new HashMap<>();
        Map<Integer, Map<Integer, Queue<LocalDateTime>>> nestPhaseStartDateTimeMap = new HashMap<>();

        for (ApsTask currentTask : collect) {

            // 判断是否为最后一道工序，如果是取上级，如果不是取上一道工序
            // 判断父级是否等于当前工序或者小于当前工序，如果小于，则累加到当前数量
            Optional<Integer> firstOpt = workOrderIdPhaseSeqMap.get(currentTask.getApsWorkOrderTemp().getId())
                    .keySet()
                    .stream()
                    .filter(e -> e > currentTask.getPhaseSeq())
                    .findFirst();

            LocalDateTime endDateTime = null;


            if(currentTask.getStatus().equals(5)) {
                log.info("*包号:{}, 零件名称:{}, PLMID:{}, 工序:{}, 下道工序:{}, 准备时间:{}, 开始时间:{}, 结束时间:{}, 工位:{}, 工作组:{}, 数量:{}",
                        PkgUtils.gen(orderCache.getApsOrderIdMap().get(currentTask.getApsWorkDetail().getApsOrderId()).getSeq()),
                        currentTask.getApsWorkDetail().getMaterName(),
                        currentTask.getApsWorkDetail().getPlmId(),
                        currentTask.getApsWorkDetail().getPhaseCode(),
                        firstOpt.isPresent()? "有": "无",
                        MkDateTimeUtils.toString(endDateTime),
                        MkDateTimeUtils.toString(currentTask.getApsWorkDetail().getPlanStartDateTime()),
                        MkDateTimeUtils.toString(currentTask.getApsWorkDetail().getPlanEndDateTime()),
                        currentTask.getApsWorkDetail().getStationId(),
                        currentTask.getApsWorkDetail().getGroupCode(),
                        currentTask.getApsWorkDetail().getTotalCount().intValue()
                );

                continue;
            }

            if (!firstOpt.isPresent() && currentTask.getApsWorkOrder().getLevel() > 1) {
                if(parentLastPhaseStartDateTimeMap.getOrDefault(currentTask.getApsWorkOrder().getApsOrderId(), new HashMap<>()).get(currentTask.getApsWorkDetail().getPhaseId()) == null){
                    List<ApsTask> collect1 = collect.stream().filter(e -> e.getApsWorkOrderTemp().getId().equals(currentTask.getApsWorkOrderTemp().getPid())).collect(Collectors.toList());
                    Map<Integer, List<ApsTask>> collect2 = collect1.stream().collect(Collectors.groupingBy(ApsTask::getPhaseSeq));
                    int min = Collections.min(collect2.keySet());
                    List<ApsTask> taskList = collect2.get(min);
                    List<ApsTask> collect3 = taskList.stream().sorted(Comparator.comparing((ApsTask e)->e.getApsWorkDetail().getPlanStartDateTime()).reversed()).collect(Collectors.toList());
                    BigDecimal partCount = currentTask.getApsWorkOrder().getPartCount();
                    for (ApsTask localDateTime : collect3) {
                        int count = partCount.intValue() * localDateTime.getApsWorkDetail().getTotalCount().intValue();
                        for (int i = 0; i < count; i++) {
                            parentLastPhaseStartDateTimeMap.computeIfAbsent(currentTask.getApsWorkOrder().getApsOrderId(), e -> new HashMap<>())
                                    .computeIfAbsent(currentTask.getApsWorkDetail().getPhaseId(), e -> new ArrayDeque<>())
                                    .add(localDateTime.getApsWorkDetail().getPlanStartDateTime());
                        }
                    }
                }

                int ct = currentTask.getApsWorkDetail().getTotalCount().intValue();
                Queue<LocalDateTime> queue = parentLastPhaseStartDateTimeMap.get(currentTask.getApsWorkOrder().getApsOrderId()).get(currentTask.getApsWorkDetail().getPhaseId());

                for (int i = 0; i < ct; i++) {
                    endDateTime = queue.poll();
                }
                endDateTime = endDateTime.minusHours(8);

            } else if(currentTask.getApsWorkOrder().getLevel().equals(1)){
//                continue;
            } else {
                Queue<LocalDateTime> queue = nestPhaseStartDateTimeMap.computeIfAbsent(currentTask.getApsWorkOrder().getApsOrderId(), e->new HashMap<>()).get(currentTask.getApsWorkDetail().getPhaseId());
                if(queue == null){
                    List<ApsTask> taskList = workOrderIdPhaseSeqMap.get(currentTask.getApsWorkOrderTemp().getId()).get(firstOpt.get());
                    List<LocalDateTime> collect1 = taskList.stream().flatMap(e -> Stream.generate(() -> e.getApsWorkDetail().getPlanStartDateTime()).limit(e.getApsWorkDetail().getTotalCount().intValue())).sorted(Comparator.naturalOrder()).collect(Collectors.toList());
                    queue = new ArrayDeque<>(collect1.size());
                    queue.addAll(collect1);
                }
                int ct = currentTask.getApsWorkDetail().getTotalCount().intValue();
                for (int i = 0; i < ct; i++) {
                    endDateTime = queue.poll();
                }
            }

//            if (!firstOpt.isPresent() && currentTask.getApsWorkOrder().getLevel() > 1) {
//                break;
//            }


            // 2.找工序对应的设备列表
            List<ApsMachine> machines = factoryCache.getGroupCodeMachineMap().get(currentTask.getGroupCode());
            if (CollUtil.isEmpty(machines)) {
                throw SyExceptionUtils.e("没有找到工作组:[" + currentTask.getGroupCode() + "], 对应的工序:[" + currentTask.getPhaseCode() + "]");
            }

            // 3.把此工序在该列表中依次排产
            List<ApsDetailWeekdayWrap> l = new ArrayList<>();
            for (ApsMachine machine : machines) {
//                ApsDetailWeekdayWrap scheduling = Aps2Utils.schedulingBottleneck(factoryCache, orderCache, start, machine, currentTask, apsDetailWeekdayMapper, apsWorkDetailMapper);
                ApsDetailWeekdayWrap scheduling = ApsTaskUtils.schedulingBottleneck(factoryCache, orderCache, endDateTime, machine, currentTask, apsDetailWeekdayMapper, apsWorkDetailMapper);
                l.add(scheduling);
            }

            // 4.取出时间最靠后的一次排产结果
            ApsDetailWeekdayWrap calendarWrap = l.stream().filter(e-> e.getStartDateTime() != null && e.getEndDateTime() != null).max(Comparator.comparing(ApsDetailWeekdayWrap::getStartDateTime)).orElseThrow(() -> SyExceptionUtils.e("排产异常"));

            currentTask.getApsWorkDetail().setPlanStartDateTime(calendarWrap.getStartDateTime());
            currentTask.getApsWorkDetail().setPlanEndDateTime(calendarWrap.getEndDateTime());
            currentTask.setNextTask(calendarWrap.getNext());
            calendarWrap.getPrevious().setNextTask(currentTask);
            currentTask.getApsWorkDetail().setStationId(calendarWrap.getMachine().getId());
            currentTask.setStartMachineCalendar(calendarWrap.getStartMachineCalendar());
            currentTask.setAll(calendarWrap.getAll());
            currentTask.getApsWorkDetail().setStatus(2);


//            DiffTime diffTime = diffTimeIdMap.get(currentTask.getApsWorkDetail().getId());
//            diffTime.setTargetPlanStartDateTime(calendarWrap.getStartDateTime());
//            diffTime.setTargetPlanEndDateTime(calendarWrap.getEndDateTime());
//            diffTime.setTargetStationId(calendarWrap.getMachine().getId());
//            System.out.println(diffTime);


//            if(currentTask.getApsWorkOrder().getLevel() > 2){
//                continue;
//            }
//          partLog.add
            partLog.add(String.format("包号:%s, 零件名称:%s, PLMID:%s, 工序:%s, 下道工序:%s, 开始时间:%s, 结束时间:%s, 工位:%s, 工作组:%s, 数量:%s",
                    PkgUtils.gen(orderCache.getApsOrderIdMap().get(currentTask.getApsWorkDetail().getApsOrderId()).getSeq()),
                    currentTask.getApsWorkDetail().getMaterName(),
                    currentTask.getApsWorkDetail().getPlmId(),
                    currentTask.getApsWorkDetail().getPhaseCode(),
                    firstOpt.isPresent()? "有": "无",
                    MkDateTimeUtils.toString(currentTask.getApsWorkDetail().getPlanStartDateTime()),
                    MkDateTimeUtils.toString(currentTask.getApsWorkDetail().getPlanEndDateTime()),
                    currentTask.getApsWorkDetail().getStationId(),
                    currentTask.getApsWorkDetail().getGroupCode(),
                    currentTask.getApsWorkDetail().getTotalCount().intValue()));
        }


        // 先给各项赋值时间
        List<ApsWorkDetailTemp> workDetailTempList = orderCache.getTaskList().stream().map(ApsTask::getApsWorkDetailTemp).collect(Collectors.toList());
        for (ApsWorkDetailTemp apsWorkDetailTemp : workDetailTempList) {

            if (apsWorkDetailTemp.getApsWorkOrder().getPlanStartDateTime() == null || apsWorkDetailTemp.getApsWorkDetail().getPlanStartDateTime().isBefore(apsWorkDetailTemp.getApsWorkOrder().getPlanStartDateTime())) {
                apsWorkDetailTemp.getApsWorkOrder().setPlanStartDateTime(apsWorkDetailTemp.getApsWorkDetail().getPlanStartDateTime());
            }

            if (apsWorkDetailTemp.getApsWorkOrder().getPlanEndDateTime() == null || apsWorkDetailTemp.getApsWorkDetail().getPlanEndDateTime().isAfter(apsWorkDetailTemp.getApsWorkOrder().getPlanEndDateTime())) {
                apsWorkDetailTemp.getApsWorkOrder().setPlanEndDateTime(apsWorkDetailTemp.getApsWorkDetail().getPlanEndDateTime());
            }

            ApsOrder apsOrder = apsOrderIdMap.get(apsWorkDetailTemp.getApsWorkOrder().getApsOrderId());
            if(apsOrder.getPlanStartDateTime() == null || apsWorkDetailTemp.getApsWorkDetail().getPlanStartDateTime().isBefore(apsOrder.getPlanStartDateTime())){
                apsOrder.setPlanStartDateTime(apsWorkDetailTemp.getApsWorkDetail().getPlanStartDateTime());
            }
            if(apsOrder.getPlanEndDateTime() == null || apsWorkDetailTemp.getApsWorkDetail().getPlanEndDateTime().isAfter(apsOrder.getPlanEndDateTime())){
                apsOrder.setPlanEndDateTime(apsWorkDetailTemp.getApsWorkDetail().getPlanEndDateTime());
            }

            Order order = orderIdMap.get(apsWorkDetailTemp.getApsWorkOrder().getOrderId());
            if(order.getPlanStartDateTime() == null || apsOrder.getPlanStartDateTime().isBefore(order.getPlanStartDateTime())){
                order.setPlanStartDateTime(apsOrder.getPlanStartDateTime());
            }
            if(order.getPlanEndDateTime() == null || apsOrder.getPlanEndDateTime().isAfter(order.getPlanEndDateTime())){
                order.setPlanEndDateTime(apsOrder.getPlanEndDateTime());
            }

        }

        try {
            FileUtils.writeLines(new File("/home/apslog/partLog.txt"), partLog);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

    }

    public void initOrderCache(ApsSchedulingOrderCacheBo orderCache, ApsSchedulingFactoryCacheBo factoryCache) {

        // 根据已有的 orderList 初始化 Order 的 Map
        Map<Integer, Order> orderIdMap = orderCache.getOrderList().stream().collect(Collectors.toMap(BaseEntity::getId, Function.identity()));
        orderCache.setOrderIdMap(orderIdMap);

        // 根据已有的 apsOrderList 初始化 ApsOrder 的 Map
        Map<Integer, List<ApsOrder>> apsOrderOrderIdMap = orderCache.getApsOrderList().stream().collect(Collectors.groupingBy(ApsOrder::getOrderId));
        orderCache.setApsOrderOrderIdMap(apsOrderOrderIdMap);

        Map<Integer, ApsOrder> apsOrderIdMap = orderCache.getApsOrderList().stream().collect(Collectors.toMap(ApsOrder::getId, Function.identity()));
        orderCache.setApsOrderIdMap(apsOrderIdMap);

        // 初始化所有订单 BOM 的 List 和 Map
        List<OrderBom> orderBomList = orderBomMapper.lambdaQuery().in(OrderBom::getOrderId, orderCache.getOrderIdMap().keySet()).list();
        orderCache.setOrderBomList(orderBomList);

        Map<Integer,List<OrderBom>> orderBomOrderIdMap = orderBomList.stream().collect(Collectors.groupingBy(OrderBom::getOrderId));
        orderCache.setOrderBomOrderIdMap(orderBomOrderIdMap);

        Map<Integer,OrderBom> orderBomIdMap = orderBomList.stream().collect(Collectors.toMap(OrderBom::getId, Function.identity()));
        orderCache.setOrderBomIdMap(orderBomIdMap);

        // 初始化所有订单 PHASE 的 List 和 Map
        List<OrderPhase> orderPhaseList = orderPhaseMapper.lambdaQuery().in(OrderPhase::getOrderId, orderCache.getOrderIdMap().keySet()).list();
        orderCache.setOrderPhaseList(orderPhaseList);

        Map<Integer,List<OrderPhase>> orderPhaseOrderIdMap = orderPhaseList.stream().collect(Collectors.groupingBy(OrderPhase::getOrderId));
        orderCache.setOrderPhaseOrderIdMap(orderPhaseOrderIdMap);

        Map<Integer,OrderPhase> orderPhaseIdMap = orderPhaseList.stream().collect(Collectors.toMap(OrderPhase::getId, Function.identity()));
        orderCache.setOrderPhaseIdMap(orderPhaseIdMap);

        List<ApsWorkDetail> apsWorkDetailList = apsWorkDetailMapper.lambdaQuery()
                .in(ApsWorkDetail::getOrderId, orderCache.getOrderIdMap().keySet())
                .eq(ApsWorkDetail::getStatus, -1)
                .list();

        List<Integer> apsWorkOrderIds = apsWorkDetailList.stream().map(ApsWorkDetail::getApsWorkOrderId).distinct().collect(Collectors.toList());
        List<ApsWorkOrder> apsWorkOrderList = apsWorkOrderMapper.selectBatchIds(apsWorkOrderIds);

        List<ApsWorkOrderTemp> apsWorkOrderTempList = apsWorkOrderList.stream()
                .map(e -> {
                    ApsWorkOrderTemp apsWorkOrderTemp = new ApsWorkOrderTemp();
                    apsWorkOrderTemp.setId(e.getId());
                    apsWorkOrderTemp.setPid(e.getPid());
                    apsWorkOrderTemp.setApsWorkOrder(e);
                    return apsWorkOrderTemp;
                })
                .collect(Collectors.toList());
        orderCache.setApsWorkOrderTempList(apsWorkOrderTempList);
        orderCache.setApsWorkOrderTempIdMap(orderCache.getApsWorkOrderTempList().stream().collect(Collectors.toMap(ApsWorkOrderTemp::getId, Function.identity())));
        orderCache.setApsWorkOrderTempPidMap(orderCache.getApsWorkOrderTempList().stream().filter(e -> e.getPid() != null).collect(Collectors.groupingBy(ApsWorkOrderTemp::getPid, Collectors.toList())));

        List<ReverseDetail> reverseDetails = reverseDetailMapper.lambdaQuery().in(ReverseDetail::getOrderId, orderCache.getOrderIdMap().keySet()).list();
        Map<String, ReverseDetail> collect1 = reverseDetails.stream().collect(Collectors.toMap(e -> e.getOrderId() + ":" + e.getBomId() + ":" + e.getPhaseId(), Function.identity(), (e1, e2) -> e1.getReverseEndTime().isBefore(e2.getReverseEndTime()) ? e1 : e2));
        reverseDetails = collect1.values().stream().sorted(Comparator.comparing(ReverseDetail::getReverseEndTime).thenComparing(ReverseDetail::getPhaseId)).collect(Collectors.toList());
        Map<Integer, List<ReverseDetail>> reverseDetailIdMap = reverseDetails.stream().collect(Collectors.groupingBy(ReverseDetail::getOrderId));
        Map<Integer, Map<Integer, ReverseDetail>> collect = reverseDetails.stream().collect(Collectors.groupingBy(ReverseDetail::getOrderId, Collectors.toMap(ReverseDetail::getPhaseId, Function.identity())));

        orderCache.setReverseDetailList(reverseDetails);
        orderCache.setReverseDetailOrderIdMap(reverseDetailIdMap);
        orderCache.setReverseDetailOrderIdPhaseIdMap(collect);


        Map<Integer, ApsWorkOrderTemp> apsWorkOrderTempIdMap = orderCache.getApsWorkOrderTempIdMap();
        List<ApsWorkDetailTemp> apsWorkDetailTempList = new ArrayList<>();
        for (ApsWorkDetail apsWorkDetail : apsWorkDetailList) {
            ApsWorkDetailTemp temp = new ApsWorkDetailTemp();
            ApsWorkOrderTemp apsWorkOrder = apsWorkOrderTempIdMap.get(apsWorkDetail.getApsWorkOrderId());
            temp.setId(apsWorkDetail.getId());
            temp.setApsWorkOrderTemp(apsWorkOrder);
            temp.setApsWorkDetail(apsWorkDetail);
            temp.setApsWorkOrder(apsWorkOrder.getApsWorkOrder());
            apsWorkDetailTempList.add(temp);
        }
        List<ApsTask> tasks = apsWorkDetailTempList.stream()
                .map(e -> {
                    ApsTask t = new ApsTask(e.getApsWorkDetail());
                    t.setApsWorkOrderTemp(e.getApsWorkOrderTemp());
                    t.setApsWorkDetailTemp(e);
                    t.setApsWorkOrder(e.getApsWorkOrder());
                    t.setId(e.getApsWorkDetail().getId());
                    t.setConsumerStatus(1);
                    t.setConsumerCount(new BigDecimal(0));
                    return t;
                })
                .sorted(Comparator.comparing(t -> t.getApsWorkDetail().getDetailSeq()))
                .collect(Collectors.toList());
        orderCache.setTaskList(tasks);

        Map<Integer, Map<Integer, List<ApsTask>>> workOrderIdPhaseSeqMap = tasks.stream().collect(Collectors.groupingBy( e-> e.getApsWorkOrderTemp().getId(), Collectors.groupingBy(ApsTask::getPhaseSeq)));
        orderCache.setWorkOrderIdPhaseSeqMap(workOrderIdPhaseSeqMap);

        Map<Integer, List<ApsTask>> workOrderPidMap = tasks.stream().filter(e -> e.getApsWorkOrderPid() != null).collect(Collectors.groupingBy(ApsTask::getApsWorkOrderPid));
        orderCache.setWorkOrderPidMap(workOrderPidMap);

        for (Order order : orderCache.getOrderList()) {
            order.setPlanStartDateTime(null);
            order.setPlanEndDateTime(null);
        }

        for (ApsOrder apsOrder : orderCache.getApsOrderList()) {
            apsOrder.setPlanStartDateTime(null);
            apsOrder.setPlanEndDateTime(null);
        }
    }


    public void initFactoryCache(ApsSchedulingFactoryCacheBo factoryCache, ApsSchedulingOrderCacheBo orderCache) {
        // 设置工厂信息
        factoryCache.setFactoryCode(projectConfig.getFactoryCode());

        // 设置客户信息
        List<Integer> customerList = orderCache.getApsOrderList().stream().map(ApsOrder::getCustomerId).distinct().collect(Collectors.toList());
        if(CollUtil.isNotEmpty(customerList)){
            List<Customer> customers = customerMapper.selectBatchIds(customerList);
            factoryCache.setCustomers(customers);
        }

        // 工作组信息
        List<String> groupNumberString = orderPhaseMapper.selectGroupList(Wrappers.<OrderPhase>query()
                .in("order_id", orderCache.getOrderList().stream().map(BaseEntity::getId).collect(Collectors.toList()))
        );
        List<Group> groups = groupMapper.lambdaQuery().in(Group::getMyCode, groupNumberString).list();
        factoryCache.setGroups(groups);

        // 工作组工位关联
//        List<StationGroup> stationGroups = stationGroupMapper.selectList(Wrappers.<StationGroup>lambdaQuery().in(StationGroup::getGroupId, groups.stream().map(BaseEntity::getId).collect(Collectors.toList())));
//        factoryCache.setStationGroups(stationGroups);

        // 工位信息
//        List<Integer> stationIds = stationGroups.stream().map(StationGroup::getStationId).distinct().collect(Collectors.toList());
//        List<Station> stations = stationMapper.selectBatchIds(stationIds);
        List<Station> stations = stationMapper.lambdaQuery().in(Station::getGroupId, groups.stream().map(BaseEntity::getId).collect(Collectors.toList())).list();
        List<Integer> stationIds = stations.stream().map(Station::getId).collect(Collectors.toList());

        for (Station station : stations) {
            if(station.getEnterTime() == null || station.getEnterTime() < 0){
                station.setEnterTime(0);
            }

            if(station.getOutTime() == null || station.getOutTime() < 0){
                station.setOutTime(0);
            }

            if(station.getChangTime() == null || station.getChangTime() < 0){
                station.setChangTime(0);
            }
        }

        factoryCache.setStations(stations);

        // 快捷从工作组找到主工位列表
//        Map<Integer, List<StationGroup>> stationGroupMap = stationGroups.stream().filter(e -> e.getDefaultGroup().equals(1)).collect(Collectors.groupingBy(StationGroup::getGroupId));
        Map<Integer, Station> stationMap = stations.stream().collect(Collectors.toMap(BaseEntity::getId, Function.identity()));
        Map<Integer, List<Station>> stationGroupIdMap = stations.stream().collect(Collectors.groupingBy(Station::getGroupId));
        Map<String, List<Station>> masterStationMap = new HashMap<>();
        for (Group group : groups) {

//            List<StationGroup> stationGroups1 = stationGroupMap.get(group.getId());
//            if(CollUtil.isEmpty(stationGroups1)){
//                continue;
//            }

//            List<Station> value = stationGroupMap.get(group.getId())
//                    .stream()
//                    .map(e -> stationMap.get(e.getStationId()))
//                    .collect(Collectors.toList());
            List<Station> value = stationGroupIdMap.get(group.getId());

            masterStationMap.put(group.getMyCode(), value);
        }

        factoryCache.setMasterStationMap(masterStationMap);

        // 工位日历
//        List<StationWeekdayScheme> stationWeekdaySchemes = stationWeekdaySchemeMapper.selectList(Wrappers.<StationWeekdayScheme>lambdaQuery().in(StationWeekdayScheme::getStationId, stationIds));
//        List<Integer> stationIds = stationGroups.stream().map(StationGroup::getshi).distinct().collect(Collectors.toList());
        List<Integer> stationShiftIds = stations.stream().map(Station::getShiftTypeId).collect(Collectors.toList());

        List<WeekdayRule> stationWeekdayRules = weekdayRuleMapper.lambdaQuery().in(WeekdayRule::getShiftTypeId, stationShiftIds).list();
//        List<Integer> shiftTypeIds = stationWeekdaySchemes.stream().map(StationWeekdayScheme::getShiftTypeId).distinct().collect(Collectors.toList());

        List<ShiftType> shiftTypes = shiftTypeMapper.selectBatchIds(stationShiftIds);
        List<Shift> shifts = shiftMapper.selectList(Wrappers.<Shift>lambdaQuery().in(Shift::getShiftTypeId, stationShiftIds));
        List<BreakPeriod> breakPeriods = breakPeriodMapper.selectList(Wrappers.<BreakPeriod>lambdaQuery().in(BreakPeriod::getShiftId, shifts.stream().map(BaseEntity::getId).distinct().collect(Collectors.toList())));

//        factoryCache.setStationWeekdaySchemes(stationWeekdaySchemes);
        factoryCache.setWeekdayRules(stationWeekdayRules);
        factoryCache.setShiftTypes(shiftTypes);
        factoryCache.setShifts(shifts);
        factoryCache.setBreakPeriods(breakPeriods);

        // 拼装设备时间链
        LocalDate startDate = orderCache.getStartDateTime().toLocalDate();
        int day = 10;
        LocalDate endDate = startDate.plusDays(day);

        if(factoryCache.getAssemblyStartDateTime() != null && endDate.isBefore(factoryCache.getAssemblyStartDateTime().toLocalDate())){
            LocalDate localDate = factoryCache.getAssemblyStartDateTime().toLocalDate().plusDays(10);
            day = (int) startDate.until(localDate, ChronoUnit.DAYS);
            endDate = localDate;
        }

        factoryCache.setMachines(stations.stream().map(ApsMachine::new).collect(Collectors.toList()));
        factoryCache.addDay(startDate, day);

        // 生产工单占位填充
        LambdaQueryWrapper<ApsDetailWeekday> wrapper = Wrappers.lambdaQuery();
        wrapper.ge(ApsDetailWeekday::getShiftDay, startDate);
        wrapper.le(ApsDetailWeekday::getShiftDay, endDate);
        wrapper.ge(ApsDetailWeekday::getState, 2);
        wrapper.ne(ApsDetailWeekday::getState, 4);
        wrapper.in(ApsDetailWeekday::getOrderType, 1, 3, 4);
        wrapper.in(ApsDetailWeekday::getStationId, stations.stream().map(Station::getId).distinct().collect(Collectors.toList()));
        wrapper.orderByAsc(ApsDetailWeekday::getPlanStartDateTime);
        List<ApsDetailWeekday> apsDetailWeekdays = apsDetailWeekdayMapper.selectList(wrapper);



        if(CollUtil.isNotEmpty(apsDetailWeekdays)){

            List<Integer> collect1 = apsDetailWeekdays.stream().map(ApsDetailWeekday::getApsWorkDetailId).distinct().collect(Collectors.toList());
            List<ApsWorkDetail> apsWorkDetailList = apsWorkDetailMapper.selectBatchIds(collect1);
            Map<Integer, ApsWorkDetail> detailMap = apsWorkDetailList
                    .stream()
                    .filter(e-> e.getTotalCount().subtract(e.getFinishCount()).compareTo(BigDecimal.ZERO) != 0)
                    .filter(e->e.getStatus() > 1)
                    .collect(Collectors.toMap(ApsWorkDetail::getId, Function.identity()));

            factoryCache.addTasks(apsDetailWeekdays, detailMap);
        }


        Map<String, List<ApsMachine>> groupCodeMachineMap = new HashMap<>();
        Map<Integer, ApsMachine> idApsMachineMap = factoryCache.getMachines().stream().collect(Collectors.toMap(ApsMachine::getId, Function.identity()));

        for (Map.Entry<String, List<Station>> entry : masterStationMap.entrySet()) {
            List<Station> collect = entry.getValue().stream().filter(e -> e.getWorkAbility() == null).collect(Collectors.toList());
            if(CollUtil.isNotEmpty(collect)){
                throw SyExceptionUtils.e("工位{}没有工作能力", entry.getValue().get(0).getName());
            }
            groupCodeMachineMap.put(entry.getKey(), entry.getValue().stream().map(e -> idApsMachineMap.get(e.getId())).collect(Collectors.toList()));
        }

        // 激光切割工作组合并
        /*
        List<String> joinGroup = Arrays.asList("1-2_JGQG_00", "1-3_JGQG_00");
        List<ApsMachine> temp = new ArrayList<>();
        for (String groupCode : joinGroup) {
            // 取出原本工作组的数据加入缓存
            List<ApsMachine> apsMachines = groupCodeMachineMap.get(groupCode);
            if(apsMachines == null){
                continue;
            }
            temp.addAll(apsMachines);
            // 缓存的指针给加工机器，以便多个工作组共享
            groupCodeMachineMap.put(groupCode, temp);
        }
         */


        factoryCache.setGroupCodeMachineMap(groupCodeMachineMap);

        factoryCache.setIgnorePhaseCode(projectConfig.getIgnorePhaseCodeList());

        factoryCache.setPzCode(WorkshopProp.PZ_PHASE_CODE);

        factoryCache.setPzSecond(WorkshopProp.PZ_SECOND);
    }


    public void modifyBatch(ApsBatch apsBatch, ApsOrderScheduleReqVo reqVo) {
        LocalDateTime now = LocalDateTime.now();
        apsBatch.setBatchNo(now.format(DatePattern.NORM_DATETIME_FORMATTER));
        apsBatch.setSchedulingDateTime(now);
        apsBatch.setSchedulingRule(reqVo.getSchedulingRule());
    }

    public List<ApsOrder> schedule(OrderScheduleReqVo reqVo, ApsBatch apsBatch) {

        // 验证
        // 判断是否有排产中的订单，如果有则提示
        LambdaQueryWrapper<Order> scheduleOrderWrapper = Wrappers.lambdaQuery();
        scheduleOrderWrapper.eq(Order::getOrderStatus, 4);
        scheduleOrderWrapper.in(Order::getOrderType, 1, 3, 4);
        Integer scheduleOrderCount = orderMapper.selectCount(scheduleOrderWrapper);

        if (scheduleOrderCount > 0) {
            throw SyExceptionUtils.e("有排产中的订单，请稍后再试");
        }
        // 取出所有待排产的订单
        LambdaQueryWrapper<Order> preScheduleOrderWrapper = Wrappers.lambdaQuery();
        preScheduleOrderWrapper.in(Order::getOrderStatus, 3, 5);
        preScheduleOrderWrapper.in(Order::getOrderType, 1, 3, 4);
        if (apsBatch != null) {
            preScheduleOrderWrapper.eq(Order::getBatchId, apsBatch.getId());
        }
        List<Order> orders = orderMapper.selectList(preScheduleOrderWrapper);
        if (CollUtil.isEmpty(orders)) {
            throw SyExceptionUtils.e("没有待排产的订单");
        }

        List<Integer> orderIds = orders.stream().map(BaseEntity::getId).collect(Collectors.toList());

        // 对apsOrders进行分组排序
        return apsOrderMapper.lambdaQuery()
                .in(ApsOrder::getOrderId, orderIds)
                .in(ApsOrder::getOrderType, 1, 3, 4)
                .list();

    }

    @Transactional
    public void editEndDate(ApsOrderEditEndDateReqVo reqVo) {

        if(reqVo.getOrderId() == null){
            throw SyExceptionUtils.e("订单ID不能为空!");
        }

        if(CollUtil.isEmpty(reqVo.getItem())){
            throw SyExceptionUtils.e("需要包详情数据!");
        }

        for (ApsOrderEditEndDateItemReqVo item : reqVo.getItem()) {
            if(item.getId() == null){
                throw SyExceptionUtils.e("拆包ID不能为空!");
            }

            if(item.getStartDate() == null){
                throw SyExceptionUtils.e("批次到期日不能为空!");
            }

            reverseOrderMapper.lambdaUpdate()
                    .set(ReverseOrder::getDeliveryDate, item.getStartDate().toString())
                    .eq(ReverseOrder::getId, item.getId())
                    .update();

            apsOrderMapper.lambdaUpdate()
                    .set(ApsOrder::getDeliveryDate, item.getStartDate().toString())
                    .eq(ApsOrder::getReverseId, item.getId())
                    .update();

        }

        orderMapper.lambdaUpdate()
                .set(Order::getDeliveryDateTime, reqVo.getItem().get(reqVo.getItem().size()-1).getStartDate() + " 00:00:00")
                .eq(Order::getId, reqVo.getOrderId())
                .update();


    }
}
